Integrate testfragmentprogramstate into my dungeon

i was planning to use 3ds/milkshape models as walls, ceiling and ground in my dungeon and then add a normal & bumpmap to the wall blocks like the fragment program test does. it should look like this:

http://img265.imageshack.us/img265/3039/bumpjo1.jpg

i just want to use models instead of simple quads because flat walls looks rather boring. i tried to simply replace the quad by a model with texture coordinates (this one -> http://radix.hopto.org/wall.3DS) and reuse the texture coordinates for the second and third texture:

    Utils.traverseGraph(p_node, new NFunction<Spatial, Object>() {
      public Object call(@NotNull Spatial p_o) {
        if (p_o instanceof SharedMesh) {
          p_o = ((SharedMesh) p_o).getTarget();
        }
        if (p_o instanceof TriMesh) {
          final TriMesh l_mesh = (TriMesh) p_o;
          for (int i = 0; i < l_mesh.getBatchCount(); i++) {
            final TriangleBatch l_batch = l_mesh.getBatch(i);
            final FloatBuffer l_buffer = l_batch.getTextureBuffer(0);
            l_batch.setTextureBuffer(l_buffer, 1);
            l_batch.setTextureBuffer(l_buffer, 2);
            l_batch.updateRenderState();
          }
        }
        return null;
      }
    }, true);



but this totally messed up everything and i get this:
http://img252.imageshack.us/img252/4062/erroroh5.jpg

this might be the weapon texture + the desired bump map, i'm not sure
what could be wrong here?

i made some progress:

http://img172.imageshack.us/img172/3584/progressms9.jpg



this time, i loaded a 3ds model and put the testfragment-textures on it, but something is … obviously not right. how can i fix this?

Looks like the lighting is being done in the local space of the model.

if you look at the first link, you'll see that everything is fine. the only difference between the last and first screenshot is that i used new Quad() and the texture coordinates from testfragmentprogramstate instead of loading a model and copying the texture coordinates provided for the first texture unit.

what you cannot see is that the bump also seems to be "some kind of inverted". it also "moves" in a way that reminds me of a magic mushroom trip when i move the camera.

i noticed the test applies different coordinates for the bump & normal map - maybe this is one of the problems? do i have to mirror the normal/bump map?


The texture coordinate data should be copied to the 2nd and 3rd texture units on the model. Looking at the last screenshot, it seems like your normals might be incorrectly smoothed across the plane, which causes light to bleed where it shouldn't.

why is the fragment test doing this

 FloatBuffer tex1 = BufferUtils.createVector2Buffer(4);
        for (int x = 0; x < 4; x++)
            tex1.put(1.0f).put(0.0f);
        q.setTextureBuffer(0, tex1, 1);
       
        FloatBuffer tex2 = BufferUtils.createVector2Buffer(4);
        for (int x = 0; x < 4; x++)
            tex2.put(0.0f).put(1.0f);
        q.setTextureBuffer(0, tex2, 2);



if i can just copy and use the same tex coords? the test is using different ones

the normals are correct. if i disable the bump & normal mapping, the error is gone (and so are the bumps, of course)

i still bet on the tex coords being the culprit.

i tried modifying the fragment test and made it use the original tex coords instead of creating different ones and got a similar error. the lighting wasn't a circle anymore, but a line.



i modified the test which now reproduces the error just by changing the texture coords:

/*
 * Copyright (c) 2003-2006 jMonkeyEngine
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jmetest.renderer.state;

import java.nio.FloatBuffer;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.image.Texture;
import com.jme.light.PointLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.SceneElement;
import com.jme.scene.SharedNode;
import com.jme.scene.SharedMesh;
import com.jme.scene.shape.Quad;
import com.jme.scene.state.CullState;
import com.jme.scene.state.FragmentProgramState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.VertexProgramState;
import com.jme.util.TextureManager;
import com.jme.util.geom.BufferUtils;


/**
 * Demonstrates the use of the GL_ARB_fragment_program extension in jME. Uses a parallax
 * mapping technique outlined in the paper "Parallax Mapping with Offset Limiting:
 * A PerPixel Approximation of Uneven Surfaces".
 * @author Eric Woroshow
 * @version $Id: TestFragmentProgramState.java,v 1.11 2007/08/21 20:11:07 nca Exp $
 */
public class TestFragmentProgramState extends SimpleGame {
    private static final Logger logger = Logger
            .getLogger(TestFragmentProgramState.class.getName());

    private final static String BRICK_TEX = "jmetest/data/images/rockwall2.jpg";
    private final static String BRICK_HEIGHT = "jmetest/data/images/rockwall_height2.jpg";
    private final static String BRICK_NRML = "jmetest/data/images/rockwall_normal2.jpg";
    private final static String BRICK_VP = "jmetest/data/images/bump_parallax.vp";
    private final static String BRICK_FP = "jmetest/data/images/bump_parallax.fp";

    /** Light positioning */
    private float angle0 = 0.0f, angle1 = 0.0f;

    /**
     * Entry point for the test.
     * @param args command line arguments; unused
     */
    public static void main(String[] args) {
        TestFragmentProgramState app = new TestFragmentProgramState();
        app.setDialogBehaviour(ALWAYS_SHOW_PROPS_DIALOG);
        app.start();
    }

    private void initLights( ) {
        //Set up two lights in the scene
        PointLight light0 = new PointLight();
        light0.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
        light0.setLocation(new Vector3f(2f, 4f, 1f));
        light0.setEnabled(true);

        PointLight light1 = new PointLight();
        light1.setDiffuse(new ColorRGBA(1.0f, 0.5f, 0.0f, 1.0f));
        light1.setLocation(new Vector3f(2f, 2f, 1f));
        light1.setEnabled(true);

        lightState.detachAll();
        lightState.setEnabled(true);
        lightState.attach(light0);
        lightState.attach(light1);
        lightState.setGlobalAmbient(new ColorRGBA(0,0,0,1));
        rootNode.setRenderState(lightState);
    }

    protected void simpleInitGame() {
        //Set up cull state
        CullState cs = display.getRenderer().createCullState();
        cs.setCullMode(CullState.CS_BACK);
        cs.setEnabled(true);

        //Basic brick texture
        TextureState brick = display.getRenderer().createTextureState();

        Texture tex = TextureManager.loadTexture(
                           TestFragmentProgramState.class.getClassLoader().getResource(BRICK_TEX),
                           Texture.MM_LINEAR_LINEAR,
                           Texture.FM_LINEAR);
        tex.setWrap(Texture.WM_WRAP_S_WRAP_T);

        //Height map of the brick wall
        Texture height = TextureManager.loadTexture(
                            TestFragmentProgramState.class.getClassLoader().getResource(BRICK_HEIGHT),
                            Texture.MM_LINEAR_LINEAR,
                            Texture.FM_LINEAR);
        height.setWrap(Texture.WM_WRAP_S_WRAP_T);

        //Normal map of the brick wall
        Texture normal = TextureManager.loadTexture(
                            TestFragmentProgramState.class.getClassLoader().getResource(BRICK_NRML),
                            Texture.MM_LINEAR_LINEAR,
                            Texture.FM_LINEAR);
        normal.setWrap(Texture.WM_WRAP_S_WRAP_T);

        brick.setTexture(tex, 0);
        brick.setTexture(normal, 1);
        brick.setTexture(height, 2);

        brick.setEnabled(true);

        VertexProgramState vert = display.getRenderer().createVertexProgramState();
        FragmentProgramState frag = display.getRenderer().createFragmentProgramState();
        //Ensure the extensions are supported, else exit immediately
        if (!vert.isSupported() || !frag.isSupported()) {
            logger.severe("Your graphics card does not support vertex or fragment programs, and thus cannot run this test.");
            quit();
        }

        //Load vertex program
        vert.load(TestFragmentProgramState.class.getClassLoader().getResource(BRICK_VP));
        vert.setEnabled(true);

        //Load fragment program
        frag.load(TestFragmentProgramState.class.getClassLoader().getResource(BRICK_FP));
        frag.setEnabled(true);

        Quad q = new Quad("wall", 10f, 10f);
        //Set up textures
        q.setRenderState(brick);


      if (false) {//some tex coord magic is going on here
        FloatBuffer tex1 = BufferUtils.createVector2Buffer(4);
        for (int x = 0; x < 4; x++)
          tex1.put(1.0f).put(0.0f);
        q.setTextureBuffer(0, tex1, 1);

        FloatBuffer tex2 = BufferUtils.createVector2Buffer(4);
        for (int x = 0; x < 4; x++)
          tex2.put(0.0f).put(1.0f);
        q.setTextureBuffer(0, tex2, 2);
      } else  {
        q.setTextureBuffer(0, q.getTextureBuffer(0, 0), 1);
        q.setTextureBuffer(0, q.getTextureBuffer(0, 0), 2);

      }


        //Set up ARB programs
        q.setRenderState(vert);
        q.setRenderState(frag);

        q.setRenderState(cs);

        initLights();
      for (int i = 0;i<10;i++)
      {
        for (int j = 0;j<10;j++)
        {
          final SharedMesh l_mesh = new SharedMesh("", q);
          l_mesh.getLocalTranslation().addLocal(j*10,i*10,0);
          rootNode.attachChild(l_mesh);

        }

      }
        rootNode.setCullMode(SceneElement.CULL_NEVER);
    }

    protected void simpleUpdate() {
        angle0 += 2 * tpf;
        angle1 += 4 * tpf;

        ((PointLight)lightState.get(0)).setLocation(new Vector3f(2.0f * FastMath.cos(angle0), 2.0f * FastMath.sin(angle0), 1.5f));
        ((PointLight)lightState.get(1)).setLocation(new Vector3f(2.0f * FastMath.cos(angle1), 2.0f * FastMath.sin(angle1), 1.5f));
    }
}



i played around a bit, and nothing seems to make sense at all.

if i use a single colored normal & bump map (so texture coordinates shouldn't matter at all), i get the lighting error, too - so it has to be tex coord independent. but why can i reproduce it in the test by changing the tex coords?

the tex coords themselves don't even make sense - 1/0,1/0,1/0,1/0 means the same pixel in one of the edges is streched along the whole quad. how can this work?