Translating in Y direction


Hi,

For some strange reason I cannot understand, when I do setLocalTranslation(new Vector3f(0, 0.05f, 0)) to my Geometry objects, the geometry object moves downward in my screen. Have you had such an experience?

Is your camera upside down?


My camera is set up like this.

cam.setParallelProjection(true);
cam.setFrustum(100, 1000, -10f, 10f, 10f, -10f);

Vector3f loc = new Vector3f(0, 0, 20);
Vector3f left = new Vector3f(-1, 0, 0);
Vector3f up = new Vector3f(0, 1, 0);
Vector3f look = new Vector3f(0, 0, -1);
cam.setFrame(loc, left, up, look);

I think it is not upside down.

What is their initial location, before the change to (0, 0.05, 0)? Also, are they attached to a parent node which is rotated upside down? Other than that I really have no idea.

The initial location of the object is at the origin. There is no rotations done prior to the translation…

Try changing:

        cam.setFrustum(100, 1000, -10f, 10f, 10f, -10f);

to

        cam.setFrustum(100, 1000, -10f, 10f, -10f, 10f);

OK,



I will do that soon.


/*

  • Copyright © 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.

    */



    import java.awt.BorderLayout;

    import java.awt.Canvas;

    import java.awt.Color;

    import java.awt.Dimension;

    import java.awt.Font;

    import java.awt.Point;

    import java.awt.event.ComponentAdapter;

    import java.awt.event.ComponentEvent;

    import java.awt.event.InputEvent;

    import java.awt.event.MouseAdapter;

    import java.awt.event.MouseEvent;

    import java.awt.event.MouseMotionListener;

    import java.awt.event.MouseWheelEvent;

    import java.awt.event.MouseWheelListener;

    import java.util.concurrent.Callable;



    import javax.swing.JFrame;

    import javax.swing.JPanel;



    import com.jme.math.FastMath;

    import com.jme.math.Quaternion;

    import com.jme.math.Vector3f;

    import com.jme.renderer.Camera;

    import com.jme.renderer.ColorRGBA;

    import com.jme.scene.Geometry;

    import com.jme.scene.Node;

    import com.jme.scene.SceneElement;

    import com.jme.scene.Text;

    import com.jme.scene.state.RenderState;

    import com.jme.scene.state.TextureState;

    import com.jme.scene.state.ZBufferState;

    import com.jme.system.DisplaySystem;

    import com.jme.util.GameTaskQueue;

    import com.jme.util.GameTaskQueueManager;

    import com.jmex.awt.JMECanvas;

    import com.jmex.awt.SimpleCanvasImpl;



    public class Test extends JFrame {

        int width = 640, height = 480;



        MyImplementor impl;

        private CameraHandler camhand;

        private Canvas glCanvas;

        private Node root;

        private Geometry grid;



        public static void main(String[] args) {

            new Test();

        }



        public Test() {

            try {

                init();

                setLocationRelativeTo(null);

                setVisible(true);

                new Thread() {

                    {

                        setDaemon(true);

                    }



                    public void run() {

                        try {

                            while (true) {

                                if (isVisible())

                                    glCanvas.repaint();

                                Thread.sleep(2);

                            }

                        } catch (InterruptedException e) {

                        }

                    }

                }.start();



            } catch (Exception ex) {

            }

        }



        private void init() throws Exception {

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            setFont(new Font("Arial", 0, 12));



            JPanel canvasPanel = new JPanel();

            canvasPanel.setLayout(new BorderLayout());

            canvasPanel.add(getGlCanvas(), BorderLayout.CENTER);



            getContentPane().add(canvasPanel, BorderLayout.CENTER);



            setSize(new Dimension(1024, 768));

        }



        private Color makeColor(ColorRGBA rgba, boolean useAlpha) {

            return new Color(rgba.r, rgba.g, rgba.b, (useAlpha ? rgba.a : 1f));

        }



        private ColorRGBA makeColorRGBA(Color color) {

            return new ColorRGBA(color.getRed() / 255f, color.getGreen() / 255f,

                    color.getBlue() / 255f, color.getAlpha() / 255f);

        }



        protected Canvas getGlCanvas() {

            if (glCanvas == null) {



                glCanvas = DisplaySystem.getDisplaySystem().createCanvas(width, height);

                glCanvas.setMinimumSize(new Dimension(100, 100));



                glCanvas.addComponentListener(new ComponentAdapter() {

                    public void componentResized(ComponentEvent ce) {

                        doResize();

                    }

                });



                camhand = new CameraHandler();



                glCanvas.addMouseWheelListener(camhand);

                glCanvas.addMouseListener(camhand);

                glCanvas.addMouseMotionListener(camhand);



                // Important! Here is where we add the guts to the canvas:

                impl = new MyImplementor(width, height);



                ((JMECanvas) glCanvas).setImplementor(impl);



                Callable<?> exe = new Callable() {

                    public Object call() {

                        forceUpdateToSize();

                        return null;

                    }

                };

                GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);

            }

            return glCanvas;

        }



        public void forceUpdateToSize() {

            // force a resize to ensure proper canvas size.

            glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() + 1);

            glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() - 1);

        }



        class CameraHandler extends MouseAdapter implements MouseMotionListener,

                MouseWheelListener {

            Point last = new Point(0, 0);

            Vector3f focus = new Vector3f();

            private Vector3f vector = new Vector3f();

            private Quaternion rot = new Quaternion();



            public void mouseDragged(final MouseEvent arg0) {

                Callable<?> exe = new Callable() {

                    public Object call() {

                        int difX = last.x - arg0.getX();

                        int difY = last.y - arg0.getY();

                        int mult = arg0.isShiftDown() ? 10 : 1;

                        last.x = arg0.getX();

                        last.y = arg0.getY();



                        int mods = arg0.getModifiers();

                        if ((mods & InputEvent.BUTTON1_MASK) != 0) {

                            rotateCamera(Vector3f.UNIT_Y, difX * 0.0025f);

                            rotateCamera(impl.getRenderer().getCamera().getLeft(),

                                    -difY * 0.0025f);

                        }

                        if ((mods & InputEvent.BUTTON2_MASK) != 0 && difY != 0) {

                            zoomCamera(difY * mult);

                        }

                        if ((mods & InputEvent.BUTTON3_MASK) != 0) {

                            panCamera(-difX, -difY);

                        }

                        return null;

                    }

                };

                GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

                        .enqueue(exe);

            }



            public void mouseMoved(MouseEvent arg0) {

            }



            public void mousePressed(MouseEvent arg0) {

                last.x = arg0.getX();

                last.y = arg0.getY();

            }



            public void mouseWheelMoved(final MouseWheelEvent arg0) {

                Callable<?> exe = new Callable() {

                    public Object call() {

                        zoomCamera(arg0.getWheelRotation()

                                * (arg0.isShiftDown() ? -100 : -20));

                        return null;

                    }

                };

                GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

                        .enqueue(exe);

            }



            public void recenterCamera() {

                Callable<?> exe = new Callable() {

                    public Object call() {

                        Camera cam = impl.getRenderer().getCamera();

                        Vector3f.ZERO.subtract(focus, vector);

                        cam.getLocation().addLocal(vector);

                        focus.addLocal(vector);

                        cam.onFrameChange();

                        return null;

                    }

                };

                GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

                        .enqueue(exe);

            }



            private void rotateCamera(Vector3f axis, float amount) {

                Camera cam = impl.getRenderer().getCamera();

                if (axis.equals(cam.getLeft())) {

                    float elevation = -FastMath.asin(cam.getDirection().y);

                    amount = Math.min(Math.max(elevation + amount,

                            -FastMath.HALF_PI), FastMath.HALF_PI)

                            - elevation;

                }

                rot.fromAngleAxis(amount, axis);

                cam.getLocation().subtract(focus, vector);

                rot.mult(vector, vector);

                focus.add(vector, cam.getLocation());

                rot.mult(cam.getLeft(), cam.getLeft());

                rot.mult(cam.getUp(), cam.getUp());

                rot.mult(cam.getDirection(), cam.getDirection());

                cam.normalize();

                cam.onFrameChange();

            }



            private void panCamera(float left, float up) {

                Camera cam = impl.getRenderer().getCamera();

                cam.getLeft().mult(left, vector);

                vector.scaleAdd(up, cam.getUp(), vector);

                cam.getLocation().addLocal(vector);

                focus.addLocal(vector);

                cam.onFrameChange();

            }



            private void zoomCamera(float amount) {

                Camera cam = impl.getRenderer().getCamera();

                float dist = cam.getLocation().distance(focus);

                amount = dist - Math.max(0f, dist - amount);

                cam.getLocation().scaleAdd(amount, cam.getDirection(),

                        cam.getLocation());

                cam.onFrameChange();

            }

        }



        protected void doResize() {

            if (impl != null) {

                impl.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());

                if (impl.getCamera() != null) {

                    Callable<?> exe = new Callable() {

                        public Object call() {

                            impl.getCamera().setFrustumPerspective(

                                    45.0f,

                                    (float) glCanvas.getWidth()

                                            / (float) glCanvas.getHeight(), 1,

                                    10000);

                            return null;

                        }

                    };

                    GameTaskQueueManager.getManager()

                            .getQueue(GameTaskQueue.RENDER).enqueue(exe);

                }

            }

        }



        class MyImplementor extends SimpleCanvasImpl {



            private static final int GRID_LINES = 51;

            private static final float GRID_SPACING = 100f;



            /

            * The root node of our text.

            */

            protected Node fpsNode;



            /


            * Displays all the lovely information at the bottom.

            */

            protected Text fps;



            /

            * This is used to recieve getStatistics calls.

            */

            protected StringBuffer tempBuffer = new StringBuffer();



            /


            * This is used to display print text.

            /

            protected StringBuffer updateBuffer = new StringBuffer(30);



            public MyImplementor(int width, int height) {

                super(width, height);

            }



            public void simpleSetup() {

                renderer.setBackgroundColor(makeColorRGBA(new Color(0, 0, 0)));

    cam.setParallelProjection(true);

    cam.setFrustum(100, 1000, -10f, 10f, 10f, -10f);



    Vector3f loc = new Vector3f(0, 0, 20);

    Vector3f left = new Vector3f(-1, 0, 0);

    Vector3f up = new Vector3f(0, 1, 0);

    Vector3f look = new Vector3f(0, 0, -1);

    cam.setFrame(loc, left, up, look);



                root = rootNode;



                // Then our font Text object.

                /
    * This is what will actually have the text at the bottom. /

                fps = Text.createDefaultTextLabel("FPS label");

                fps.setCullMode(SceneElement.CULL_NEVER);

                fps.setTextureCombineMode(TextureState.REPLACE);



                // Finally, a stand alone node (not attached to root on purpose)

                fpsNode = new Node("FPS node");

                fpsNode.setRenderState(fps.getRenderState(RenderState.RS_ALPHA));

                fpsNode.setRenderState(fps.getRenderState(RenderState.RS_TEXTURE));

                fpsNode.attachChild(fps);

                fpsNode.setCullMode(SceneElement.CULL_NEVER);



                renderer.enableStatistics(true);



                root.attachChild(grid = createGrid());

                grid.updateRenderState();



                ZBufferState zbuf = renderer.createZBufferState();

                zbuf.setWritable(false);

                zbuf.setEnabled(true);

                zbuf.setFunction(ZBufferState.CF_LEQUAL);



                fpsNode.updateGeometricState(0, true);

                fpsNode.updateRenderState();



    /***********************************************************************/

    /
    HERE !!!                                                                                                                /

    /
    Comment out the setLocalTranslation and run. Then un-comment and run the second time.  /

    /
    I get the box lowered.                                                                                              */

    /*********************************************************************/           



    com.jme.scene.shape.Box box = new com.jme.scene.shape.Box("hello", new Vector3f(0, 0, 0), new Vector3f(0.1f, 0.1f, 0.1f));

    root.attachChild(box);



    box.setLocalTranslation(new Vector3f(0, 0.05f, 0));           

            }



            public void simpleUpdate() {

                updateBuffer.setLength(0);

                updateBuffer.append("FPS: ").append((int) timer.getFrameRate())

                        .append(" - ");

                updateBuffer.append(renderer.getStatistics(tempBuffer));

                /
    Send the fps to our fps bar at the bottom. */

                fps.print(updateBuffer);

            }



            @Override

            public void simpleRender() {

                fpsNode.draw(renderer);

                renderer.clearStatistics();

            }



            private Geometry createGrid() {

                Vector3f[] vertices = new Vector3f[GRID_LINES * 2 * 2];

                float edge = GRID_LINES / 2 * GRID_SPACING;

                for (int ii = 0, idx = 0; ii < GRID_LINES; ii++) {

                    float coord = (ii - GRID_LINES / 2) * GRID_SPACING;

                    vertices[idx++] = new Vector3f(-edge, 0f, coord);

                    vertices[idx++] = new Vector3f(+edge, 0f, coord);

                    vertices[idx++] = new Vector3f(coord, 0f, -edge);

                    vertices[idx++] = new Vector3f(coord, 0f, +edge);

                }

                Geometry grid = new com.jme.scene.Line("grid", vertices, null,

                        null, null);

                grid.getBatch(0).getDefaultColor().set(ColorRGBA.darkGray.clone());

                return grid;

            }

        }

    }

Look for the comment HERE.


The problem is solved by adding the following line before setting the camera.

            cam = renderer.createCamera(width, height);

Thanks !


Wait, I still have the problem. Sorry.

The view changed to perspective projection.

I still cannot get the view to have correct Y translation when the view is in parallel projection.

Any help ??

Thanks.

A simple attempt: Try using cam.lookAt(); instead of setting the frame yourself and see if it helps.


I want to move only one object in the scene, though.

I just realized that in parallel projection, all my pictures are upside down, in contrast to the perspective projection  !!

It is strangely flipped in only y-direction.



Is parallel projection using different coordinate system??

Did you ever try this?

Try changing:
        cam.setFrustum(100, 1000, -10f, 10f, 10f, -10f);
to
        cam.setFrustum(100, 1000, -10f, 10f, -10f, 10f);

Yes, and the same result.





I think the problem is in the buffer. When the renderer displays back buffer, it has a problem…somewhere in the doRender().


Finally, I got the coordinates right.

I had a setFrustumPerspective() in the doResize() method. I changed that to setFrustum.

Also, as nymon suggested, I had to change setFrustum to cam.setFrustum(100, 1000, -10f, 10f, -10f, 10f);

Thanks.


/*

  • Copyright © 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.

    */



    import java.awt.BorderLayout;

    import java.awt.Canvas;

    import java.awt.Color;

    import java.awt.Dimension;

    import java.awt.Font;

    import java.awt.Point;

    import java.awt.event.ComponentAdapter;

    import java.awt.event.ComponentEvent;

    import java.awt.event.InputEvent;

    import java.awt.event.MouseAdapter;

    import java.awt.event.MouseEvent;

    import java.awt.event.MouseMotionListener;

    import java.awt.event.MouseWheelEvent;

    import java.awt.event.MouseWheelListener;

    import java.util.concurrent.Callable;



    import javax.swing.JFrame;

    import javax.swing.JPanel;



    import com.jme.math.FastMath;

    import com.jme.math.Quaternion;

    import com.jme.math.Vector3f;

    import com.jme.renderer.Camera;

    import com.jme.renderer.ColorRGBA;

    import com.jme.scene.Geometry;

    import com.jme.scene.Node;

    import com.jme.scene.SceneElement;

    import com.jme.scene.Text;

    import com.jme.scene.state.RenderState;

    import com.jme.scene.state.TextureState;

    import com.jme.scene.state.ZBufferState;

    import com.jme.system.DisplaySystem;

    import com.jme.util.GameTaskQueue;

    import com.jme.util.GameTaskQueueManager;

    import com.jmex.awt.JMECanvas;

    import com.jmex.awt.SimpleCanvasImpl;



    public class Test extends JFrame {

    int width = 640, height = 480;



    MyImplementor impl;

    private CameraHandler camhand;

    private Canvas glCanvas;

    private Node root;

    private Geometry grid;



    public static void main(String[] args) {

    new Test();

    }



    public Test() {

    try {

    init();

    setLocationRelativeTo(null);

    setVisible(true);

    new Thread() {

    {

    setDaemon(true);

    }



    public void run() {

    try {

    while (true) {

    if (isVisible())

    glCanvas.repaint();

    Thread.sleep(2);

    }

    } catch (InterruptedException e) {

    }

    }

    }.start();



    } catch (Exception ex) {

    }

    }



    private void init() throws Exception {

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    setFont(new Font("Arial", 0, 12));



    JPanel canvasPanel = new JPanel();

    canvasPanel.setLayout(new BorderLayout());

    canvasPanel.add(getGlCanvas(), BorderLayout.CENTER);



    getContentPane().add(canvasPanel, BorderLayout.CENTER);



    setSize(new Dimension(1024, 768));

    }



    private Color makeColor(ColorRGBA rgba, boolean useAlpha) {

    return new Color(rgba.r, rgba.g, rgba.b, (useAlpha ? rgba.a : 1f));

    }



    private ColorRGBA makeColorRGBA(Color color) {

    return new ColorRGBA(color.getRed() / 255f, color.getGreen() / 255f,

    color.getBlue() / 255f, color.getAlpha() / 255f);

    }



    protected Canvas getGlCanvas() {

    if (glCanvas == null) {



    glCanvas = DisplaySystem.getDisplaySystem().createCanvas(width, height);

    glCanvas.setMinimumSize(new Dimension(100, 100));



    glCanvas.addComponentListener(new ComponentAdapter() {

    public void componentResized(ComponentEvent ce) {

    doResize();

    }

    });



    camhand = new CameraHandler();



    glCanvas.addMouseWheelListener(camhand);

    glCanvas.addMouseListener(camhand);

    glCanvas.addMouseMotionListener(camhand);



    // Important! Here is where we add the guts to the canvas:

    impl = new MyImplementor(width, height);



    ((JMECanvas) glCanvas).setImplementor(impl);



    Callable<?> exe = new Callable() {

    public Object call() {

    forceUpdateToSize();

    return null;

    }

    };

    GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);

    }

    return glCanvas;

    }



    public void forceUpdateToSize() {

    // force a resize to ensure proper canvas size.

    glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() + 1);

    glCanvas.setSize(glCanvas.getWidth(), glCanvas.getHeight() - 1);

    }



    class CameraHandler extends MouseAdapter implements MouseMotionListener,

    MouseWheelListener {

    Point last = new Point(0, 0);

    Vector3f focus = new Vector3f();

    private Vector3f vector = new Vector3f();

    private Quaternion rot = new Quaternion();



    public void mouseDragged(final MouseEvent arg0) {

    Callable<?> exe = new Callable() {

    public Object call() {

    int difX = last.x - arg0.getX();

    int difY = last.y - arg0.getY();

    int mult = arg0.isShiftDown() ? 10 : 1;

    last.x = arg0.getX();

    last.y = arg0.getY();



    int mods = arg0.getModifiers();

    if ((mods & InputEvent.BUTTON1_MASK) != 0) {

    rotateCamera(Vector3f.UNIT_Y, difX * 0.0025f);

    rotateCamera(impl.getRenderer().getCamera().getLeft(),

    -difY * 0.0025f);

    }

    if ((mods & InputEvent.BUTTON2_MASK) != 0 && difY != 0) {

    zoomCamera(difY * mult);

    }

    if ((mods & InputEvent.BUTTON3_MASK) != 0) {

    panCamera(-difX, -difY);

    }

    return null;

    }

    };

    GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

    .enqueue(exe);

    }



    public void mouseMoved(MouseEvent arg0) {

    }



    public void mousePressed(MouseEvent arg0) {

    last.x = arg0.getX();

    last.y = arg0.getY();

    }



    public void mouseWheelMoved(final MouseWheelEvent arg0) {

    Callable<?> exe = new Callable() {

    public Object call() {

    zoomCamera(arg0.getWheelRotation()
  • (arg0.isShiftDown() ? -100 : -20));

    return null;

    }

    };

    GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

    .enqueue(exe);

    }



    public void recenterCamera() {

    Callable<?> exe = new Callable() {

    public Object call() {

    Camera cam = impl.getRenderer().getCamera();

    Vector3f.ZERO.subtract(focus, vector);

    cam.getLocation().addLocal(vector);

    focus.addLocal(vector);

    cam.onFrameChange();

    return null;

    }

    };

    GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER)

    .enqueue(exe);

    }



    private void rotateCamera(Vector3f axis, float amount) {

    Camera cam = impl.getRenderer().getCamera();

    if (axis.equals(cam.getLeft())) {

    float elevation = -FastMath.asin(cam.getDirection().y);

    amount = Math.min(Math.max(elevation + amount,

    -FastMath.HALF_PI), FastMath.HALF_PI)
  • elevation;

    }

    rot.fromAngleAxis(amount, axis);

    cam.getLocation().subtract(focus, vector);

    rot.mult(vector, vector);

    focus.add(vector, cam.getLocation());

    rot.mult(cam.getLeft(), cam.getLeft());

    rot.mult(cam.getUp(), cam.getUp());

    rot.mult(cam.getDirection(), cam.getDirection());

    cam.normalize();

    cam.onFrameChange();

    }



    private void panCamera(float left, float up) {

    Camera cam = impl.getRenderer().getCamera();

    cam.getLeft().mult(left, vector);

    vector.scaleAdd(up, cam.getUp(), vector);

    cam.getLocation().addLocal(vector);

    focus.addLocal(vector);

    cam.onFrameChange();

    }



    private void zoomCamera(float amount) {

    Camera cam = impl.getRenderer().getCamera();

    float dist = cam.getLocation().distance(focus);

    amount = dist - Math.max(0f, dist - amount);

    cam.getLocation().scaleAdd(amount, cam.getDirection(),

    cam.getLocation());

    cam.onFrameChange();

    }

    }



    protected void doResize() {

    if (impl != null) {

    impl.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());

    if (impl.getCamera() != null) {

    Callable<?> exe = new Callable() {

    public Object call() {

    impl.getCamera().setFrustum(-10, 100, -10f, 10f, -10f, 10f);

    return null;

    }

    };

    GameTaskQueueManager.getManager()

    .getQueue(GameTaskQueue.RENDER).enqueue(exe);

    }

    }

    }



    class MyImplementor extends SimpleCanvasImpl {



    private static final int GRID_LINES = 51;

    private static final float GRID_SPACING = 100f;



    /**
  • The root node of our text.

    */

    protected Node fpsNode;



    /**
  • Displays all the lovely information at the bottom.

    */

    protected Text fps;



    /**
  • This is used to recieve getStatistics calls.

    /

    protected StringBuffer tempBuffer = new StringBuffer();



    /*

      * This is used to display print text.

      /

    protected StringBuffer updateBuffer = new StringBuffer(30);



    public MyImplementor(int width, int height) {

    super(width, height);

    }



    public void simpleSetup() {

    renderer.setBackgroundColor(makeColorRGBA(new Color(0, 0, 0)));

    cam.setParallelProjection(true);

    cam.setFrustum(-10, 100, -10f, 10f, -10f, 10f);



    Vector3f loc = new Vector3f(0, 0, 20);

    Vector3f left = new Vector3f(-1, 0, 0);

    Vector3f up = new Vector3f(0, 1, 0);

    Vector3f look = new Vector3f(0, 0, -1);

    cam.setFrame(loc, left, up, look);



    root = rootNode;



    // Then our font Text object.

    /
    This is what will actually have the text at the bottom. /

    fps = Text.createDefaultTextLabel("FPS label");

    fps.setCullMode(SceneElement.CULL_NEVER);

    fps.setTextureCombineMode(TextureState.REPLACE);



    // Finally, a stand alone node (not attached to root on purpose)

    fpsNode = new Node("FPS node");

    fpsNode.setRenderState(fps.getRenderState(RenderState.RS_ALPHA));

    fpsNode.setRenderState(fps.getRenderState(RenderState.RS_TEXTURE));

    fpsNode.attachChild(fps);

    fpsNode.setCullMode(SceneElement.CULL_NEVER);



    renderer.enableStatistics(true);



    root.attachChild(grid = createGrid());

    grid.updateRenderState();



    ZBufferState zbuf = renderer.createZBufferState();

    zbuf.setWritable(false);

    zbuf.setEnabled(true);

    zbuf.setFunction(ZBufferState.CF_LEQUAL);



    fpsNode.updateGeometricState(0, true);

    fpsNode.updateRenderState();



    /
    /

    /
    HERE !!!                                                                                /

    /
    Comment out the setLocalTranslation and run. Then un-comment and run the second time.   
    /

    /
    I get the box lowered.                                                                  /

    /
    ****/           



    com.jme.scene.shape.Box box = new com.jme.scene.shape.Box("hello", new Vector3f(0, 0, 0), new Vector3f(1f, 1f, 1f));         

    root.attachChild(box);



    box.setLocalTranslation(new Vector3f(0, 0.5f, 0));           

    }



    public void simpleUpdate() {

    updateBuffer.setLength(0);

    updateBuffer.append("FPS: ").append((int) timer.getFrameRate())

    .append(" - ");

    updateBuffer.append(renderer.getStatistics(tempBuffer));

    /** Send the fps to our fps bar at the bottom. */

    fps.print(updateBuffer);

    }



    @Override

    public void simpleRender() {

    fpsNode.draw(renderer);

    renderer.clearStatistics();

    }



    private Geometry createGrid() {

    Vector3f[] vertices = new Vector3f[GRID_LINES * 2 * 2];

    float edge = GRID_LINES / 2 * GRID_SPACING;

    for (int ii = 0, idx = 0; ii < GRID_LINES; ii++) {

    float coord = (ii - GRID_LINES / 2) * GRID_SPACING;

    vertices[idx++] = new Vector3f(-edge, 0f, coord);

    vertices[idx++] = new Vector3f(+edge, 0f, coord);

    vertices[idx++] = new Vector3f(coord, 0f, -edge);

    vertices[idx++] = new Vector3f(coord, 0f, +edge);

    }

    Geometry grid = new com.jme.scene.Line("grid", vertices, null,

    null, null);

    grid.getBatch(0).getDefaultColor().set(ColorRGBA.darkGray.clone());

    return grid;

    }

    }

    }

Great! I'm glad you got it figured out.  8)