OrientedShape3D not working

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

OrientedShape3D not working

unixnerd
Hope this is the right forum for this.

Just got jogl working after migrating from Java3D 1.5 :-)

I tried Java3D 1.6 a few years ago, in fact it might have been an older version of jogl my memory is poor. But back then I noticed the problem I'm having now.

My program makes heavy use of OrientedShape3D to create text labels that always face the user regardless of rotation. Alas they're not moving at all.

Any ideas? Thanks in advance.
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

gouessej
Administrator
Hello

Actually, OrientedShape3D comes from Java3D, not from JOGL, it's a billboard node. Is your problem a regression (i.e did it work as expected in Java3D 1.5)? Can you reproduce your problem on a small self-contained example please?
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

unixnerd
It was fine in Java3D 1.5 but may have been broken in 1.6.

I'll try and put an exemple together. I use these in loads of places.

Is there an alternative?
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

gouessej
Administrator
Maybe rather start from scratch, create a basic scene and add a single oriented shape into it. I can't imagine that OrientedShape3D has remained broken for years without someone else reporting it. If it works in a rudimentary example, you'll have to understand what breaks it when you complicate the source code.

P.S: It's not a JOGL bug because com.ardor3d.scenegraph.extension.BillboardNode works whereas JogAmp's Ardor3D Continuation relies on JOGL 2.
Julien Gouesse | Personal blog | Website
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

philjord
Hi, if you can get me a simple example I can help, or if required a big fat dump of code might help.

Have you set up a bounding sphete or bounding Leaf node so the billboard behavior is triggered?

(Sorry not in front of a computer right now)
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

basti
In reply to this post by unixnerd
Hello unixnerd,
I've made a test scene in which you can walk around, while the Text3D in the OrientedShape3D always faces the camera.
I'm not sure if this is what you meant but i hope it helps.

OrientedShapeTest.zip
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

unixnerd
Still no luck with this. Any ideas? (anti-aliasing not enabled either, separate post)



		Text3D labelText = new Text3D(font3d, "test", new Point3f(0f,0f,0f));
		labelText.setAlignment(Text3D.ALIGN_CENTER);
		
		int mode = OrientedShape3D.ROTATE_ABOUT_POINT // trying flags out of desperation!
				| OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
				| OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
				| OrientedShape3D.ALLOW_POINT_WRITE	| OrientedShape3D.ALLOW_POINT_READ
				| OrientedShape3D.ALLOW_AXIS_WRITE	| OrientedShape3D.ALLOW_AXIS_READ;
			
		OrientedShape3D textLabelShape = new OrientedShape3D(labelText, appBlue, mode, new Point3f(0.0f,0.0f,0.0f));
						
		Transform3D labelTrans = new Transform3D();
		labelTrans.rotX(Math.PI);
		labelTrans.setScale(.05);		
		labelTrans.setTranslation(new Vector3f((float)e.x3d, (float)e.y3d, (float)e.z3d));
		
		TransformGroup textLabelTransform = new TransformGroup(labelTrans);
		textLabelTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		textLabelTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		textLabelTransform.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
		textLabelTransform.addChild(textLabelShape);
		
		BranchGroup newGroup = new BranchGroup();		
		newGroup.setCapability(BranchGroup.ALLOW_DETACH);
		newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
		newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
		newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); 
		newGroup.addChild(textLabelTransform);
		newGroup.compile();

		tg.addChild(newGroup);
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

basti
Hello unixnerd,
i think i'm able to reproduce your issue of OrientedShape3D not moving, if you look at this test scene.

If you set mode to 0 in the constructor it should rotate with the camera.
I would also remove the line "t3dShape.rotX(Math.PI);" in addOrientedShape() since it effectively flips and mirrors the text.

best regards
basti  


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.function.Consumer;
import javax.swing.JFrame;
import org.jogamp.java3d.Appearance;
import org.jogamp.java3d.BoundingBox;
import org.jogamp.java3d.Bounds;
import org.jogamp.java3d.BranchGroup;
import org.jogamp.java3d.Canvas3D;
import org.jogamp.java3d.Font3D;
import org.jogamp.java3d.FontExtrusion;
import org.jogamp.java3d.Locale;
import org.jogamp.java3d.OrientedShape3D;
import org.jogamp.java3d.PhysicalBody;
import org.jogamp.java3d.PhysicalEnvironment;
import org.jogamp.java3d.Text3D;
import org.jogamp.java3d.Transform3D;
import org.jogamp.java3d.TransformGroup;
import org.jogamp.java3d.View;
import org.jogamp.java3d.ViewPlatform;
import org.jogamp.java3d.VirtualUniverse;
import org.jogamp.java3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import org.jogamp.java3d.utils.universe.SimpleUniverse;
import org.jogamp.vecmath.Color3f;
import org.jogamp.vecmath.Point3d;
import org.jogamp.vecmath.Point3f;
import org.jogamp.vecmath.Vector3d;

/**
 * Test Scene demonstrating OrientedShape3D.
 *
 * When walking around the scene the OrientedShape3D should face the camera:
 *  up/down          = forwards/backwards
 *  left/right          = rotate left/right
 *  ALT+left/right   = step left/right
 *  page up/down  = change pitch
 *  enter               = reset to initial position/rotation
 *
 * Note:
 *  - Tested with Java3D 1.7.1 final
 *  - Should work with prior versions but name-space of imports would have to be
 *    adjusted.
 *
 * @author basti
 */
public class OrientedShapeTestScene extends JFrame {
   
    public static void main(String[] args) {
        new OrientedShapeTestScene().start();
    }
   
    private final String text = "Java3D";
    private final Font font = new Font(Font.MONOSPACED, Font.PLAIN, 1);
    private final Vector3d initCameraPos = new Vector3d(0d, 0.5d, 5d);
    private final double backClipDistance = 100d;
    private final Vector3d shapePos = new Vector3d();
    private final Text3D text3D;
    private final OrientedShape3D shape;
    private final Canvas3D canvas;
    private final BranchGroup root;
    private final Transform3D t3dCamera = new Transform3D();
    private final TransformGroup tgCamera = new TransformGroup(t3dCamera);
    private final View view;
    private final ViewPlatform camera;
    private final PhysicalBody body;
    private final PhysicalEnvironment env;
    private final Locale locale;
    private final Transform3D t3dShape = new Transform3D();
    private final TransformGroup tgShape = new TransformGroup(t3dShape);
   
    public OrientedShapeTestScene() {
        System.setProperty("sun.awt.noerasebackground", "true");
       
        this.canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        this.root = new BranchGroup();
        this.view = new View();
        this.body = new PhysicalBody();
        this.env = new PhysicalEnvironment();
        this.camera = new ViewPlatform();
        this.locale = new Locale(new VirtualUniverse());
       
        this.text3D = new Text3D(new Font3D(font, new FontExtrusion()), text, new Point3f(0.0f,0.0f,0.0f));
        text3D.setAlignment(Text3D.ALIGN_CENTER);
       
        int mode = OrientedShape3D.ROTATE_ABOUT_POINT
            | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
            | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
            | OrientedShape3D.ALLOW_POINT_WRITE | OrientedShape3D.ALLOW_POINT_READ
            | OrientedShape3D.ALLOW_AXIS_WRITE | OrientedShape3D.ALLOW_AXIS_READ;
        //int mode = 0;
       
        Appearance appBlue = new Appearance();
        this.shape = new OrientedShape3D(text3D, appBlue, mode, new Point3f(0.0f,0.0f,0.0f));
       
        buildScene();
        initFrame();
    }
   
    private void start() {
        setVisible(true);
    }
   
    private void initFrame() {
        setTitle("OrientedShape3D Test Scene");
        setPreferredSize(new Dimension(500, 500));
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas.requestFocus();
    }

    private void initCanvas() {
        canvas.setStereoEnable(false);
        canvas.setDoubleBufferEnable(true);
        add(canvas, BorderLayout.CENTER);
       
        canvas.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                    translateCameraToInitialPosition();
                }
            }
        });
    }
   
    private void buildScene() {
        BranchGroup viewGroup = new BranchGroup();
       
        initCanvas();
        addKeyNavigatorBehavior();
        addObjectsToScene();
        translateCameraToInitialPosition();
       
        tgCamera.addChild(camera);
        viewGroup.addChild(tgCamera);
        view.setBackClipDistance(backClipDistance);
        view.setPhysicalBody(body);
        view.setPhysicalEnvironment(env);
        view.addCanvas3D(canvas);
        view.attachViewPlatform(camera);
        locale.addBranchGraph(root);
        locale.addBranchGraph(viewGroup);
    }

    private void translateCameraToInitialPosition() {
        t3dCamera.setIdentity();
        t3dCamera.setTranslation(initCameraPos);
        tgCamera.setTransform(t3dCamera);
    }

    private void addKeyNavigatorBehavior() {
        KeyNavigatorBehavior behavior = new KeyNavigatorBehavior(tgCamera);
        Point3d lower = new Point3d(-100, -100, -100);
        Point3d upper = new Point3d(100, 100, 100);
        Bounds bounds = new BoundingBox(lower, upper);
       
        behavior.setSchedulingBoundingLeaf(null);
        behavior.setSchedulingBounds(bounds);
        root.addChild(behavior);
        tgCamera.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    }
   
    private void addObjectsToScene() {
        addOrientedShape();
        addGrid();
    }

    private void addGrid() {
        Consumer<BranchGroup> addToRoot = bgGrid -> root.addChild(bgGrid);
        HorizontalSquaredGrid grid = new HorizontalSquaredGrid(addToRoot);
        Color3f green = new Color3f(0f, 1f, 0f);
       
        grid.addGrid(-100, 100, 0, green);
    }

    private void addOrientedShape() {
        //TODO: not needed
        t3dShape.rotX(Math.PI);
       
        t3dShape.setScale(.05);
        t3dShape.setTranslation(shapePos);
        tgShape.setTransform(t3dShape);
       
        tgShape.addChild(shape);
       
        TransformGroup tg = new TransformGroup();
        BranchGroup newGroup = new BranchGroup();
        newGroup.setCapability(BranchGroup.ALLOW_DETACH);
        newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        newGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
        newGroup.addChild(tgShape);
        newGroup.compile();

        tg.addChild(newGroup);
       
        root.addChild(tg);
    }
}

//------------------


import java.util.List;
import org.jogamp.java3d.Appearance;
import org.jogamp.java3d.ColoringAttributes;
import org.jogamp.java3d.LineArray;
import org.jogamp.java3d.LineAttributes;
import org.jogamp.java3d.Shape3D;
import org.jogamp.java3d.TransformGroup;
import org.jogamp.vecmath.Color3f;
import org.jogamp.vecmath.Point3d;

/**
 * Lines in a specified color. Done with a Shape3D backed by a LineArray.
 *
 * @author basti
 */
public class ColoredLineList {
    private final List<Point3d> points;
    private final ColoringAttributes coloringAttributes;
    private final float lineWidth;
    private final LineArray array;
    private final LineAttributes lineAttributes;
    private final Shape3D shape;
    private final Appearance appearance;
   
    /**
     * Constructs new instance with line width of 10 pixels.
     * @param points list of Point3d to be created
     * @param color color used
     */
    public ColoredLineList(List<Point3d> points, Color3f color) {
        this(points, color, 10f);
    }
   
    /**
     * Constructs new instance.
     * @param points list of Point3d to be created
     * @param color color used
     * @param lineWidth line width in pixels
     */
    public ColoredLineList(List<Point3d> points, Color3f color,
            float lineWidth) {
       
        this.points = points;
        this.coloringAttributes = new ColoringAttributes(color,
                ColoringAttributes.FASTEST);
        this.lineWidth = lineWidth;
        this.array = buildLine();
        this.lineAttributes = new LineAttributes();
        this.shape = new Shape3D(array);
        this.appearance = new Appearance();
    }
   
    /**
     * Builds lines and adds them to a TransformGroup
     * @param tg parent to add Shape3D to
     */
    public void addToParent(TransformGroup tg) {
        addCoordinates();
        lineAttributes.setLineWidth(lineWidth);
        appearance.setColoringAttributes(coloringAttributes);
        appearance.setLineAttributes(lineAttributes);
        shape.setAppearance(appearance);
        tg.addChild(shape);
    }

    private void addCoordinates() {
        array.setCoordinates(0, points.toArray(new Point3d[]{}));
    }

    private LineArray buildLine() {
        return new LineArray(points.size(), LineArray.COORDINATES);
    }
}

//--------------------


import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.jogamp.java3d.BranchGroup;
import org.jogamp.java3d.Transform3D;
import org.jogamp.java3d.TransformGroup;
import org.jogamp.vecmath.Color3f;
import org.jogamp.vecmath.Point3d;

/**
 * A horizontal squared grid backed by a Shape3D with added LineArray.
 *
 * @author basti
 */
public class HorizontalSquaredGrid {
    private final Consumer<BranchGroup> addToRoot;
    private final float lineWidth;

    /**
     * Constructs new instance with line width of 1 pixel.
     * @param addToRoot lambda expecting BranchGroup containing grid
     */
    public HorizontalSquaredGrid(Consumer<BranchGroup> addToRoot) {
        this(addToRoot, 1f);
    }
   
    /**
     * Constructs new instance.
     * @param addToRoot lambda expecting BranchGroup containing grid
     * @param lineWidth line width in pixels
     */
    public HorizontalSquaredGrid(Consumer<BranchGroup> addToRoot,
            float lineWidth) {
       
        this.addToRoot = addToRoot;
        this.lineWidth = lineWidth;
    }
   
    /**
     * Builds grid and adds it to scene.
     *
     * Example:
     *  calling: grid.addGrid(-100, 100, 0, green); results in green grid with:
     *   lowerCorner = (-100, 0, -100)
     *   upperCorner = (100, 0, 100)
     *
     * @param lowerEnd lowest value for x and z axis
     * @param upperEnd highest value for x and z axis
     * @param y height of grid
     * @param color color of grid
     */
    public void addGrid(int lowerEnd, int upperEnd, double y, Color3f color) {
        List<Point3d> points = new ArrayList<Point3d>();
       
        for (int i = lowerEnd; i <= upperEnd; i++) {
            points.add(new Point3d(lowerEnd, y, i));
            points.add(new Point3d(upperEnd, y, i));
            points.add(new Point3d(i, y, lowerEnd));
            points.add(new Point3d(i, y, upperEnd));
        }
       
        ColoredLineList lines = new ColoredLineList(points, color, lineWidth);
        addLines(lines);
    }
   
    private void addLines(ColoredLineList lines) {
        Transform3D t3dModel = new Transform3D();
        TransformGroup tgGrid = new TransformGroup(t3dModel);
        BranchGroup bgGrid = new BranchGroup();
       
        lines.addToParent(tgGrid);
        bgGrid.addChild(tgGrid);
        addToRoot.accept(bgGrid);
    }
}

Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

unixnerd
You're an inspiration! :-) Setting the "mode" flags to zero made them rotate! They seem to be doing it in an odd way and facing the "wrong" place though. Friday night here now, will experiment later......... Can't thank you enough for helping!
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

basti
Thanks,

i realized something about this line:

int mode = OrientedShape3D.ROTATE_ABOUT_POINT // trying flags out of desperation!
                                | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
                                | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
                                | OrientedShape3D.ALLOW_POINT_WRITE | OrientedShape3D.ALLOW_POINT_READ
                                | OrientedShape3D.ALLOW_AXIS_WRITE | OrientedShape3D.ALLOW_AXIS_READ;

you're mixing alignment mode with capabilities which is probably how this effectively resulted in
OrientedShape3D.ROTATE_NONE (value 2)

I suggested to set mode to 0 (OrientedShape3D.ROTATE_ABOUT_AXIS) which should result in rotating around y-axis only, but is not ideal when looking directly down from high altitudes since text remains vertical to x/z plane.
Alternatively OrientedShape3D.ROTATE_ABOUT_POINT would rotate along all 3 axis. The pivot point is the one specified via constructor new Point3f(0,0,0) (relative position)

Judging from your screen capture it almost looks like all texts have the same absolute pivot point and circling around it...
anyway just my 2 cents

basti
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

philjord
Basti,
You beat me to it, I was just typing out the same commnet.

Mode in the constructor only accepts a single value
 ROTATE_ABOUT_AXIS, ROTATE_ABOUT_POINT, or ROTATE_NONE
which is not a bitwise flag.

The capability bit settings should be sent to setCapabilities

So this
int mode = OrientedShape3D.ROTATE_ABOUT_POINT
            | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
            | OrientedShape3D.ALLOW_MODE_WRITE | OrientedShape3D.ALLOW_MODE_READ
            | OrientedShape3D.ALLOW_POINT_WRITE | OrientedShape3D.ALLOW_POINT_READ
            | OrientedShape3D.ALLOW_AXIS_WRITE | OrientedShape3D.ALLOW_AXIS_READ;
        //int mode = 0;
       
        Appearance appBlue = new Appearance();
        this.shape = new OrientedShape3D(text3D, appBlue, mode, new Point3f(0.0f,0.0f,0.0f));


should be

int mode = OrientedShape3D.ROTATE_ABOUT_POINT );
       
Appearance appBlue = new Appearance();
this.shape = new OrientedShape3D(text3D, appBlue, mode, new Point3f(0.0f,0.0f,0.0f));
 /**
     * Sets the specified capability bit.  Note that only one capability bit
     * may be set per method invocation--capability bits cannot be ORed
     * together.
     * @param bit the bit to set
     * @exception RestrictedAccessException if this object is part of live
     * or compiled scene graph
     */
this.shape.setCapability( OrientedShape3D.ALLOW_MODE_WRITE);
this.shape.setCapability( OrientedShape3D.ALLOW_MODE_READ);
this.shape.setCapability( OrientedShape3D.ALLOW_MODE_WRITE );
this.shape.setCapability( OrientedShape3D.ALLOW_MODE_READ);
this.shape.setCapability( OrientedShape3D.ALLOW_POINT_WRITE );
this.shape.setCapability( OrientedShape3D.ALLOW_POINT_READ);
this.shape.setCapability( OrientedShape3D.ALLOW_AXIS_WRITE );
this.shape.setCapability( OrientedShape3D.ALLOW_AXIS_READ);




Which is annoyingly long winded, I've never noticed the single bit per call requirement.
   
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

basti
@philjord
oh yes... not being able to or capabilities together was eluding me as well.

@unixnerd
Having slept on this, i would say setting mode to ROTATE_ABOUT_AXIS like this:

int mode = OrientedShape3D.ROTATE_ABOUT_AXIS //equal to 0
OrientedShape3D textLabelShape = new OrientedShape3D(labelText, appBlue, mode, new Point3f(0.0f,0.0f,0.0f));

may not be what you want, because the rotation point is set to (0,0,0) instead of default (0,0,1)
Have you tried using the default constructor and setting appearance and geometry separately ?

OrientedShape3D textLabelShape = new OrientedShape3D();
textLabelShape.setGeometry(labelText);
textLabelShape.setAppearance(appBlue);

This should set the default values:
alignment mode : ROTATE_ABOUT_AXIS
alignment axis : Y-axis (0,1,0)
rotation point : (0,0,1)

source: OrientedShape3D.java line 185
Reply | Threaded
Open this post in threaded view
|

Re: OrientedShape3D not working

unixnerd
Bit of a late reply on this, not been well.

new OrientedShape3D(text, appLbl, OrientedShape3D.ROTATE_ABOUT_POINT, new Point3f(0.0f,0.0f,0.0f));

Fixed my problem. I think I just had the wrong arguments before, the way they work is different to 1.5.x and what I was doing before was probably invalid but worked by some fluke.