Displaying 3D models in GUI node

Hi,

In my game, I want to display a spatial in GUI node and remove from rootNode when a user clicks on it and place it back when the user clicks on empty surface.

For that I’m using the code

    private void pickSpatial(Spatial s) {
        shootables.detachChild(s);
        // Display spatial on GUI node
        //scale = s.getWorldScale();
        s2 = s.clone();
        s2.setLocalTranslation(25,25,0);
        s2.scale(20);
        s2.rotate(r, 0, -r);
        app.getGuiNode().attachChild(s2);
        //app.getGuiNode().setLocalTranslation(0, 0, 0);
        
        
    }
    
    private void placeSpatial (Spatial s) {
        
        /*
         * Process the position to adjust it accordingle if a magnet or some other
         * component wants to change it. 
         */
        
        // Remove from GUI node
        app.getGuiNode().detachChild(s2);
        s2 = null;

To display it on GUI node I need to scale up he spatial as one WU is only 1 pixel in guiNode. So if I want to use the same spatial, I need to store its scale info in a variable so that I can restore the same scale back when placing. I tried storing this info using various methods but when I tried restoring it back to old scale, I did not get the same size spatial. How can I store scale info and later set it back so that I get the same size spatial as earlier?

I tried another way by first creating a clone and attaching it to gui node and later turning it to null after deattaching it. Does this successfully garbage collect the spatial (by turning it to null)???

Spatials get garbage collected just like any other object.

You could attach your own parent node to the guiNode and then apply scale to it instead of the objects. Attach the objects to that parent instead of directly to the guiNode.

…then you wouldn’t have to keep track of the scale.

Also, scale() is relative to the current scale. You probably wanted setLocalScale() anyway.

1 Like
@pspeed said: Spatials get garbage collected just like any other object.

You could attach your own parent node to the guiNode and then apply scale to it instead of the objects. Attach the objects to that parent instead of directly to the guiNode.

…then you wouldn’t have to keep track of the scale.

Also, scale() is relative to the current scale. You probably wanted setLocalScale() anyway.

Nice idea… Thanks

Hi,

I’ve also tried to add a Spatial to the guiNode but whenever I do, the Spatial is kind of “see through” like this

Do any of you guys know why this happens, and how to fix it?

Thanks

I think there’s very few z depth in the gui and that is why spatials can look bad there.

The way I resolved it is by outputting a frameBuffer to the texture of an element in the gui.
Here is the code (nb: done with toneGodGUI, but same principles for other 2D libs):

    private void setupModelViewer(Node node) {
        offCamera = new Camera(WIDTH, HEIGHT);

        modelView = game.getRenderManager().createPreView("model3DView", offCamera);
        modelView.setClearFlags(true, true, true);
        modelView.setBackgroundColor(ColorRGBA.DarkGray);

        //setup framebuffer's cam
        offCamera.setFrustumPerspective(30, 3f, 1f, 500f);
        offCamera.setLocation(new Vector3f(0, 0, -6));
        offCamera.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

        // create offscreen framebuffer
        offBuffer = new FrameBuffer(WIDTH, HEIGHT, 1);

        //setup framebuffer's texture
        offTex = new Texture2D(WIDTH, HEIGHT, Image.Format.RGBA8);
//        offTex.setMinFilter(Texture.MinFilter.Trilinear);
//        offTex.setMagFilter(Texture.MagFilter.Bilinear);

        //setup framebuffer to use texture
        offBuffer.setDepthBuffer(Image.Format.Depth);
        offBuffer.setColorTexture(offTex);

        //set viewport to render to offscreen framebuffer
        modelView.setOutputFrameBuffer(offBuffer);

        node.updateGeometricState();

        modelView.attachScene(node);
    }

    private void displayModelView() {
        Element displayModel = new Element(screen, "displayModelElement",
                new Vector2f(5, 50),
                new Vector2f(WIDTH, HEIGHT),
                Vector4f.ZERO, "Interface/Launcher/corsicansInSpace.png");//replace img by small blank one
        displayModel.getMaterial().setTexture("ColorMap", offTex);
        displayModel.getMaterial().getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Back);
        mainTabControl.addTabChild(TAB_CHILD, displayModel);
    }

Works fine for my needs, but not knowledgeable enough to know how good/efficient a solution that is.

1 Like

I’m sorry, but is there a tutorial on toneGodGUI? I actually am just beginning to use jmonkeyengine so this is quite confusing to me.

1 Like

ToneGodGUI is a 2D lib made by toneGod.
General documentation: Exciting news! And… um… new Documentation… dun dun duuuun
Or to get all the threads linked to that project: http://hub.jmonkeyengine.org/c/projects/tonegodgui

For 2D lib, you have a choice between nifty (officially supported) and toneGodGUI and Lemur.

In my snippet, setupModelViewer() is “generic”; only displayModelView() is linked to the 2D lib. So you can use any lib or do it yourself and use this… just set the texture of the element in 2D (displayModel.getMaterial().setTexture(“ColorMap”, offTex);).

I’ve found it easier to follow easy paths to get the architecture going and only focus on pretty/specific difficulties later on. So maybe you shouldn’t be focusing on this kind of stuff from the get-go.

1 Like

Sorry for reanimating this thread from the book of dead topics:

I’m currently in need to render a 3D compass or a Jaime monkey “to the guiNode”.
(well, not exactly that - I could make another gui3dNode or other idea)
I’m not using anything that’s not part of the jME 3 (3.0) SDK (so no ToneGod UI).
I want the background to be transparent (show the things in the rootNode behind the compass).
I did something like that for a jME 2.0 project but can’t find the old code and it might not work with jME 3 anyways.

So, if anybody has a good solution to this problem - don’t hesitate to post it or to contact me.
Could be something simple, like another render pass after everything was rendered (how would I do that?).
I will try the description from loopies without ToneGod.
If there is no solution, I will use a simple 2D fallback.

If it’s a single mesh (or simple meshes) then just put it in the gui node and scale it up. Done.

Else you will want to create a separate main viewport with its own camera. Create an app state to manage the updateLogicalState()/updateGeometricState() of that viewport’s root node (that you create and have to manage yourself).

2 Likes

No, the monkey does not render correctly when attached to gui node.
See the link of @NoUserName from Jan’15 - that’s what happens.
It also happens to my 3D compass since it’s 7 geometries, not 1.

Does the viewport allow for transparent background?

Maybe I could do RTT (render-to-texture) to get a transparent background?

:chimpanzee_confused:

1 Like

Of course it does. One glance through the javadoc should show you the clear flags that can be set.

2 Likes

Oh. Why didn’t I think of that sooner? That’s the ideal solution for my minimap problem too.

2 Likes

I use TGG because it comes with lots of controls such as lists, tables etc that are very useful for my project.
In your case, if you don’t need all of that, you might be better short-cutting TGG and only creating a quad, attaching it to the gui and setting it’s texture about the same way. Anyway, if you have a question, you know where to find me… I’ll be in my cave trying to master… fire :D.

2 Likes

Hello, can someone explain me what i do wrong or what i understand incorrectly?

As i know based on https://wiki.jmonkeyengine.org/jme3/advanced/hud.html

1f of size in guiNode of 3d object is like 1 pixel.

So i made test auto-scale of objects like:

        Point startPoint = entry.getKey();
        Spatial spat = item.getSpatial();
        ///////////////////////////////////////////////
        BoundingVolume bound = spat.getWorldBound();
        float currentScale = Inversion.app.utility.BoundingScaleComputation(bound);
        System.out.println("currentScale");
        System.out.println(currentScale);
        float destMaxScale = 30;//Math.max(width * pixelSpace, height * pixelSpace);
        System.out.println("destMaxScale");
        System.out.println(destMaxScale);
        float applyRatio = destMaxScale/currentScale;
        spat.scale(applyRatio);
        ///////////////////////////////////////////////
        float xBound = ((BoundingBox)spat.getWorldBound()).getXExtent();
        spat.setLocalTranslation(xBound + startPoint.x * pixelSpace, startPoint.y * pixelSpace, 1000);
        ///////////////////////////////////////////////
        System.out.println("new world bound");
        System.out.println(spat.getWorldBound());
        System.out.println("new getLocalScale");
        System.out.println(spat.getLocalScale());
        System.out.println("new getWorldScale");
        System.out.println(spat.getWorldScale());
        System.out.println("new getWorldTransform");
        System.out.println(spat.getWorldTransform());
        ///////////////////////////////////////////////
        node.attachChild(spat);

Problem is that output seems correct, and world values are like 30 px or less, but in gui object is much bigger.

output in console:

currentScale
0.198355
destMaxScale
30.0
new world bound
BoundingBox [Center: (33.80051, 20.738544, 1000.355) xExtent: 29.999996 yExtent: 23.096859 zExtent: 15.956055]
new getLocalScale
(22.686596, 22.686596, 22.686596)
new getWorldScale
(22.686596, 22.686596, 22.686596)
new getWorldTransform
Transform[ 29.999996, 0.0, 1000.0]
[ 0.0, 0.0, 0.0, 1.0]
[ 22.686596 , 22.686596, 22.686596]

My question is, why 3d object is then like 60px instead of 23px (based on size in gui)

here is screen:

(black box in corner is 30x30px)

@pspeed

I don’t understand… your bounding box says it’s 60 also. xExtent = 30, yExtent = 30 == 60x60

I don’t know where your other scales come from.

But in the guiNode 1 pixel = 1 unit as long as you haven’t set the scale differently on the guiNode.

1 Like

omg, right, seems i just thought xExtent is not from center :smiley: but its 2x if from center

ok thanks, i wrote it too fast :slight_smile: