Reflection Map for moving objects?

I have a moving object and a sky box. When I try to use TextureCubeMap to make the object reflect the environment,  I get the reflection, but is static - when I move the object, the reflection does not move.  In TestCubeMap testcase, the object is fixed, but rotates - in that case, the reflections are properly shown.  I modified that test so now the object does not rotate, but simply moves with the camera.  Now, when I move the camera around, the object also moves, but the reflection on it does not.  How do I make it to reflect the skybox in proper way when the object moves?



Here is the ready to run test code (based on TestCubeMap with some mods):



package jmetest.renderer;

import java.nio.FloatBuffer;

import org.lwjgl.util.vector.Matrix4f;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingBox;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.image.TextureCubeMap;
import com.jme.image.Texture.ApplyMode;
import com.jme.image.Texture.CombinerFunctionRGB;
import com.jme.image.Texture.EnvironmentalMapMode;
import com.jme.image.Texture.MagnificationFilter;
import com.jme.image.Texture.MinificationFilter;
import com.jme.image.Texture.WrapMode;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.TexCoords;
import com.jme.scene.Spatial.CullHint;
import com.jme.scene.Spatial.LightCombineMode;
import com.jme.scene.shape.Quad;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;
import com.jme.util.geom.BufferUtils;

/**
* <code>TestCubeMap</code>
*
* @author Joshua Slack
* @version $Id: $
*/
public class TestCubeMap1 extends SimpleGame {
   
    private Quaternion rotQuat = new Quaternion();
    private float angle = 0;
    private Vector3f axis = new Vector3f(1, 1, 0);
    private Sphere sphere;
    private Node sky;
    Texture envTex=null;

    /**
     * Entry point for the test,
     *
     * @param args
     */
    public static void main(String[] args) {
        TestCubeMap1 app = new TestCubeMap1();
        app.setConfigShowMode(ConfigShowMode.AlwaysShow);
        app.start();
    }

    float x=0;
    float y=0;
    Quaternion q=new Quaternion(1,1,1,1);
    private Vector3f qaxis = new Vector3f(0, 1, 0);
    protected void simpleUpdate() {

        Vector3f v=cam.getDirection().normalizeLocal().mult(50);
        sphere.setLocalTranslation(v);
       
       
    }

    protected void simpleInitGame() {
        sphere= new Sphere("s",30,30,10);
        sphere.setModelBound(new BoundingBox());
        sphere.updateModelBound();
        sphere.setCullHint(CullHint.Dynamic);
        sphere.copyTextureCoordinates(0, 1, 1.0f);
        sphere.scaleTextureCoordinates(0, 8);
        rootNode.attachChild(sphere);

        TextureState ts = display.getRenderer().createTextureState();
        envTex=generateCubeMapTexture();
        ts.setTexture(envTex);
        ts.getTexture().setEnvironmentalMapMode(EnvironmentalMapMode.ReflectionMap);
        ts.getTexture().setApply(ApplyMode.Combine);
        ts.getTexture().setCombineFuncRGB(CombinerFunctionRGB.AddSigned);
        sphere.setRenderState(ts);
       
        generateSky();
       
        rootNode.setCullHint(CullHint.Never);
        rootNode.setRenderQueueMode(Renderer.QUEUE_OPAQUE);
       
        cam.setLocation(new Vector3f());
        sky.getLocalTranslation().set(cam.getLocation());

    }

    private void generateSky() {
        TextureState ts;
        sky = new Node("sky");
        sky.setCullHint(CullHint.Never);
        sky.setLightCombineMode(LightCombineMode.Off);
        rootNode.attachChild(sky);

        ts = display.getRenderer().createTextureState();
        ts.setTexture(generateCubeMapTexture());
        sky.setRenderState(ts);

        ZBufferState zbuff = display.getRenderer().createZBufferState();
        zbuff.setWritable(false);
        zbuff.setEnabled(true);
        zbuff.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
        sky.setRenderState(zbuff);
        sky.setRenderQueueMode(Renderer.QUEUE_SKIP);

        Quad posXQuad = new Quad("test", 10, 10);
        FloatBuffer tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(1).put(1).put(-1);
        tbuf.put(1).put(-1).put(-1);
        tbuf.put(1).put(-1).put(1);
        tbuf.put(1).put(1).put(1);
        posXQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        posXQuad.setLocalRotation(new Quaternion(new float[] { 0,
                (float) Math.toRadians(270), 0 }));
        posXQuad.setLocalTranslation(new Vector3f(5, 0, 0));
        sky.attachChild(posXQuad);

        Quad negXQuad = new Quad("test", 10, 10);
        tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(-1).put(1).put(1);
        tbuf.put(-1).put(-1).put(1);
        tbuf.put(-1).put(-1).put(-1);
        tbuf.put(-1).put(1).put(-1);
        negXQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        negXQuad.setLocalRotation(new Quaternion(new float[] { 0,
                (float) Math.toRadians(90), 0 }));
        negXQuad.setLocalTranslation(new Vector3f(-5, 0, 0));
        sky.attachChild(negXQuad);

        Quad posYQuad = new Quad("test", 10, 10);
        tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(-1).put(1).put(-1);
        tbuf.put(1).put(1).put(-1);
        tbuf.put(1).put(1).put(1);
        tbuf.put(-1).put(1).put(1);
        posYQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        posYQuad.setLocalRotation(new Quaternion(new float[] {
                (float) Math.toRadians(90), (float) Math.toRadians(270), 0 }));
        posYQuad.setLocalTranslation(new Vector3f(0, 5, 0));
        sky.attachChild(posYQuad);

        Quad negYQuad = new Quad("test", 10, 10);
        tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(1).put(-1).put(-1);
        tbuf.put(-1).put(-1).put(-1);
        tbuf.put(-1).put(-1).put(1);
        tbuf.put(1).put(-1).put(1);
        negYQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        negYQuad.setLocalRotation(new Quaternion(new float[] {
                (float) Math.toRadians(270), (float) Math.toRadians(270), 0 }));
        negYQuad.setLocalTranslation(new Vector3f(0, -5, 0));
        sky.attachChild(negYQuad);

        Quad posZQuad = new Quad("test", 10, 10);
        tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(1).put(1).put(1);
        tbuf.put(1).put(-1).put(1);
        tbuf.put(-1).put(-1).put(1);
        tbuf.put(-1).put(1).put(1);
        posZQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        posZQuad.setLocalRotation(new Quaternion(new float[] { 0,
                (float) Math.toRadians(180), 0 }));
        posZQuad.setLocalTranslation(new Vector3f(0, 0, 5));
        sky.attachChild(posZQuad);

        Quad negZQuad = new Quad("test", 10, 10);
        tbuf = BufferUtils.createFloatBuffer(12);
        tbuf.put(-1).put(1).put(-1);
        tbuf.put(-1).put(-1).put(-1);
        tbuf.put(1).put(-1).put(-1);
        tbuf.put(1).put(1).put(-1);
        negZQuad.setTextureCoords(new TexCoords(tbuf, 3), 0);
        negZQuad.setLocalTranslation(new Vector3f(0, 0, -5));
        sky.attachChild(negZQuad);
    }

    private TextureCubeMap generateCubeMapTexture() {
        Image posX = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_posx.png"), true);
        Image negX = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_negx.png"), true);
        Image posY = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_posy.png"), true);
        Image negY = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_negy.png"), true);
        Image posZ = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_posz.png"), true);
        Image negZ = TextureManager.loadImage(TestBoxColor.class
                .getClassLoader().getResource("jmetest/data/texture/cube_face_negz.png"), true);
        Image cubeMapImage = posX;
        cubeMapImage.addData(negX.getData(0));
        cubeMapImage.addData(posY.getData(0));
        cubeMapImage.addData(negY.getData(0));
        cubeMapImage.addData(posZ.getData(0));
        cubeMapImage.addData(negZ.getData(0));
        TextureCubeMap cubeMapTex = new TextureCubeMap();
        cubeMapTex.setImage(cubeMapImage);
        cubeMapTex.setMinificationFilter(MinificationFilter.BilinearNoMipMaps);
        cubeMapTex.setMagnificationFilter(MagnificationFilter.NearestNeighbor);
        cubeMapTex.setWrap(WrapMode.EdgeClamp);
        return cubeMapTex;
    }

}

I don't think reflection maps usually work like that? (they're normally reflections of distant things, like the skybox)

The reflection map works exactly like in this example. I use skybox for it, the issue is that depending where is the object in relation of the camera, the skybox must be reflected differently.



Example:



Camera is at 0,0,0



The skybox has a mountain at direction 0,0,1 and lake at 0,0,-1 (opposite direction)

If camera looks at the object and the object is at  0,0,10  the object must reflect the lake;

If camera looks at the object and the object is at  0,0,-10  the object must reflect the mountain;