[SOLVED] BitmapText/Node always visible

I have a BitmapText Node(Label) that should be visible all the time no matter the camera position or which elements are between the label and camera. If I rotate my model then of course the BitmapText disappears behind other nodes. But this label is a description of an important element and must be allways visibile.
I didn’t find the possiblity to set the z-order or something else.
Is there an option to set a node always in foreground?

I think that you are looking for guiNode a Node variable on SimpleApplication class.

// just replace 
rootNode.attachChild(Label);
 //with
guiNode.attachChild(Label);

You want a billboard. You set the z order via the local translation really… I think this is more transparency and buckets than z order in your scene directly.

@jayfella I tried the Billborad but I don’t found the option to set the to front.

BitmapFont bitmapFont = assetManager.loadFont("Interface/Fonts/Default.fnt");
	BitmapText bitmapText = new BitmapText(bitmapFont, false);
	bitmapText.setSize(30);
	bitmapText.setText(szText);
	bitmapText.setQueueBucket(Bucket.Transparent);
	bitmapText.setColor(foreGround);
	bitmapText.setCullHint(CullHint.Never);
	
	BillboardControl billboardControl = new BillboardControl() {
		
	};
	billboardControl.setAlignment(BillboardControl.Alignment.Screen);
	
	bitmapText.addControl(billboardControl);

@oualid
I can not use the guiNode because the node is connected to another node which can change its positon and the label must be move its position, too. But the user must see this label from every camera perpective even when an other object is between camera and label. Similar to x -ray.

Put it in the translucent bucket. It will draw over EVERYTHING.

@pspeed Unfortunately, your hint doesn’t work, may be I forgot to do somethings before it works. I hope my example code will help.

public void simpleInitApp() {
        BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
        BitmapText txt = new BitmapText(fnt, false);
        txt.setBox(new Rectangle(0, 0, 6, 3));
        txt.setQueueBucket(Bucket.Translucent);
        txt.setSize( 0.5f );
        txt.setText(txtB);
        txt.setColor(ColorRGBA.Red);
        txt.setLocalTranslation(0, 0, 0);
        rootNode.attachChild(txt);
                
        Box boxForeground = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box",boxForeground);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
           geom.setMaterial(mat);
        rootNode.attachChild(geom);        
    }

The code produces the following result:

But result should be this:

Although the text is behind box, the text should be visible to the user like in the second image.

You may also have to turn off depth test. In my experience, the translucent bucket already ignores existing depth but that may be because I have a filter post processor in use.

You will have to visit the Geometry of the BitmapText, grab its material, and set its additional render state to have depth test turned off.

Edit: and note that even if you controlled the rendering order through other means (like a custom GeometryComparator) then you would also have to deal with the depth test issues… else always render the text first and then you’d have a black halo around it.

I tried your hint but I don’t get it to work. My approach is to implement my own GeometryComparator and negate the result of origin comparator. But it doesn’t work.

public class TestBitmapText3D extends SimpleApplication {

private String txtB =
"ABCDEFGHIKLMNOPQRSTUVWXYZ1234567890`~!@#$%^&*()-=_+[]\\;',./{}|:<>?";

public static void main(String[] args){
    TestBitmapText3D app = new TestBitmapText3D();
    app.start();
}

public static class LayerComparator implements GeometryComparator {
    private GeometryComparator delegate;
    
    public LayerComparator(GeometryComparator delegate) {
        this.delegate=delegate;
    }
    
    @Override
    public void setCamera(Camera cam) {
            delegate.setCamera(cam);
    }

    @Override
    public int compare( Geometry g1, Geometry g2 ) {
        System.out.println("geo = "+g1);
        System.out.println("geo = "+g2);
        return -delegate.compare(g1, g2);
    }
}

@Override
public void simpleInitApp() {        
    GeometryComparator orgComparator = getViewPort().getQueue().getGeometryComparator(Bucket.Translucent);
    getViewPort().getQueue().setGeometryComparator(Bucket.Translucent,new LayerComparator(orgComparator));
    BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
    BitmapText txt = new BitmapText(fnt, false);
    txt.setName("my-text");
    txt.setBox(new Rectangle(0, 0, 6, 3));
    txt.setQueueBucket(Bucket.Translucent);
    txt.setSize( 0.5f );
    txt.setText(txtB);
    txt.setColor(ColorRGBA.Red);
    txt.setLocalTranslation(0, 0, 0f);
    Material mattxt = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mattxt.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
    mattxt.setFloat("AlphaDiscardThreshold", .5f);
    mattxt.getAdditionalRenderState().setDepthTest(false);
    //txt.setMaterial(mattxt);
    
    rootNode.attachChild(txt);
    
    Box boxForeground = new Box(1, 1, 1);
    Geometry geom = new Geometry("Box",boxForeground);
    geom.setQueueBucket(Bucket.Translucent);
    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    
    geom.setMaterial(mat);
    rootNode.attachChild(geom);        
}

}

Why do you put the box in the translucent bucket?

Look, buckets are rendered in order. No matter what you do for a comparator… the buckets will always be rendered in order. Randomly throwing a hundred different changes in is not going to work.

Make a box. Put it in the opaque bucket.

make some text. Use a SceneGraphVisitor to change all of its materials to set depth test false. (I mean, your code doesn’t even do this… so I don’t know how you can say it doesn’t work… I already said that it’s 100% required.)

Put the text in the transparent or tranclucent bucket (both are always rendered after the opaque bucket… always. Always.)

It will work or you didn’t follow the directions or there is some code we can’t see.

@pspeed I got the solution :slight_smile: .

This lines:

fnt.getPage(0).getAdditionalRenderState().setDepthTest(false);
txt.setQueueBucket(Bucket.Translucent);

Did the trick.

Thanks to all for your help.

    public void simpleInitApp() {
    BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
    fnt.getPage(0).getAdditionalRenderState().setDepthTest(false);
    BitmapText txt = new BitmapText(fnt, false);
    txt.setName("my-text");
    txt.setBox(new Rectangle(0, 0, 6, 3));
    txt.setQueueBucket(Bucket.Translucent);
    txt.setSize( 0.5f );
    txt.setText(txtB);
    txt.setColor(ColorRGBA.Red);
    txt.setLocalTranslation(0, 0, 0f);              
    rootNode.attachChild(txt);
           
    Box boxForeground = new Box(1, 1, 1);
    Geometry geomForeground = new Geometry("Box",boxForeground);
    geomForeground.setQueueBucket(Bucket.Opaque);
    Material matForeground = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    geomForeground.setMaterial(matForeground);
    rootNode.attachChild(geomForeground);       
}
2 Likes