[SOLVED] Why does the BitmapText I'm using have a black background?


#1

Here is an example of what I’m seeing:

Here is the code I’m using for all the text you can see on the screen:

BitmapFont font = assetManager.loadFont("Interface/Fonts/Default.fnt");
BitmapText countText = new BitmapText(font, false);
countText.setSize(gameParameters.getCardHeight() / 3);
countText.setColor(ColorRGBA.White);
this.attachChild(countText);

How can I get rid of the black background?


#2

It’s related to this:

ie: you have a sorting issue.

Edit: note, Lemur ‘fixes’ fonts by turning on alpha discard if you load them through Lemur… but that’s only a partial fix. It will get rid of the blocky black background but then your text will have small borders where it has partial alpha. (And note, it’s technically not really a black background, it’s your ‘background in whatever color’ leaking through.)

Lemur also has a layered geometry comparator to force things to sort in a specific order. You can use this in your project, too… with or without the rest of Lemur.


#3

I’ve been trying to do my homework on this but having a lot of difficulty for what seems like such a fundamental 3d game engine feature. I appreciate the z-buffer issues and that it can only be accurate to a certain precision but for objects that are static and always guaranteed to be one behind the other it seems like there should be a simpler solution. First I tried to even figure out what alpha discard was and it seems like it’s a material parameter that can be set like this:

Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
material.setFloat("AlphaDiscardThreshold", .5f);
text.setMaterial(material);
text.setQueueBucket(Bucket.Transparent);

But the text in the BitmapText doesn’t have a way to set the material from what I can gather. The only reference to material that BitmapText has is the method setMaterial() but in my testing and other forum threads it seems to only affect the quad behind the text, not the text itself. I couldn’t find any specific code examples in the threads I was looking at so I took a shot in the dark with these settings but they didn’t work.

Next you mentioned and I saw multiple other threads where people suggested to set a custom geometry comparator. I never saw any code examples for that either really but I tried to do it like this:

RenderQueue rq = vm.app.getViewPort().getQueue();

rq.setGeometryComparator(Bucket.Transparent, new TransparentComparator() {
    @Override
    public int compare(Geometry o1, Geometry o2) {
        return Float.compare(o1.getWorldTranslation().getZ(), o2.getWorldTranslation().getZ());
    }
});

I also tried to use Lemur with these pom settings in maven:

<repository>
    <id>jcenter</id>
    <url>http://jcenter.bintray.com</url>
</repository>
...
<dependency>
    <groupId>com.simsilica</groupId>
    <artifactId>lemur</artifactId>
    <version>1.9.1</version>
    <type>pom</type>
</dependency>

It pulled in guava and sl4j but none of the references to Lemur classes (ie Button or TextField) are resolvable in my code like it doesn’t see the jar correctly. Looking at the Lemur documentation and API I also don’t see a text component. You mentioned specifically loading the font through Lemur so I looked for a utility like that but didn’t find it either. Any further steering?

Edit: I just set the opaque comparator in addition to the transparent comparator like this:

rq.setGeometryComparator(Bucket.Opaque, new OpaqueComparator() {
@Override
    public int compare(Geometry o1, Geometry o2) {
        return Float.compare(o1.getWorldTranslation().getZ(), o2.getWorldTranslation().getZ());
    }
});

and now the text no longer has the black background bleeding through. Why would changing the opaque comparator make the items in the transparent bucket resolve their z-order correctly?


#4

Probably because you have the text in the wrong bucket.

BitmapText is a bunch of letter quads mapped to part of a texture containing the whole alphabet.

re: the maven coordinates, I’m not sure why you’ve set the dependency as type “pom”. That seems odd. In case you missed it, here is the Lemur getting started page:

From there you can also get an overview of the standard GUI elements… like Label which is for displaying text.

Or if you just load your font’s with Lemur then they are automatically given a discard threshold:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/GuiGlobals.html#loadFont(java.lang.String)

…but that only trims the problem from the full quad down to an ugly border around the text (where alpha is non-zero).

If you’ve initialized Lemur’s GuiGlobals then it will install its own GeometryComparator that allows you to set layers using a Spatial’s user data. Or you can use the method that takes the guesswork out:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/LayerComparator.html#setLayer(com.jme3.scene.Spatial,%20int)

So, for example, if you had two objects in the regular 3D scene, both in the transparent bucket, and you always want object A to sort behind object B… then you can give one a layer of 0 and the other a layer of 1.

But in your case it might just be that you’ve put your text in the opaque bucket and text is not opaque.

From the engine’s perspective, what does “one behind the other” mean?


#5

I copied that maven dependency from this: https://bintray.com/simsilica/Sim-tools/lemur/view

Removing the pom dependency type immediately brought in the lemur jar. Thanks for the tip.I looked over the Lemur getting started pages a lot but now that I actually have the jar I will play with it more.

Here is the current visual:

This is the current working code:

RenderQueue rq = vm.app.getViewPort().getQueue();
rq.setGeometryComparator(Bucket.Transparent, new TransparentComparator() {
    @Override
    public int compare(Geometry o1, Geometry o2) {
        return Float.compare(o1.getWorldTranslation().getZ(), o2.getWorldTranslation().getZ());
    }
});
	
rq.setGeometryComparator(Bucket.Opaque, new OpaqueComparator() {
    @Override
    public int compare(Geometry o1, Geometry o2) {
        return Float.compare(o1.getWorldTranslation().getZ(), o2.getWorldTranslation().getZ());
    }
});

...

// Create pile count text
BitmapFont font = assetManager.loadFont("Interface/Fonts/Default.fnt");
countText = new BitmapText(font, false);
countText.setQueueBucket(Bucket.Transparent);
countText.setSize(gameParameters.getCardHeight() / 3);
countText.setColor(ColorRGBA.White);
this.attachChild(countText);

Both custom geometry comparators have to be set in order to stop the black bleeding but the text is in the transparent bucket.

As far as a general solution to what does one behind the other mean I can appreciate the problem. I was specifically referring to the case where objects don’t ever switch z positions and you have the camera locked always in one direction toward them. Maybe some boolean flag for defaulting the geometry comparator to the values that would quickly get transparency working in an intuitive sense for people making traditional 2d style games in the 3d engine based on the SimpleApplications default camera orientation. Which sounds similar like what you did with Lemur and the layers concept.


#6

Yes, well… because the real question is why use the 3D view if you aren’t doing anything in 3D. As soon as you do ‘something’ in 3D then generally the z-order becomes tricky again.

If the ordering of the opaque bucket matters then your text is not in the transparent bucket.

ALL transparent bucket spatials are ALWAYS drawn AFTER ALL opaque bucket spatials. It cannot be otherwise. Another problem would have been if your card was also in the transparent bucket… but then the ordering in the opaque bucket wouldn’t matter but either your transparent or opaque comparator is likely backwards. (Opaque items should be sorted by material first and then by front to back order. Transparent should be sorted back to front.)


#7

Ugh… I really hate maven. I could power a small city from the heat.


#8

The card is also in the transparent bucket. Good tip on the materials for the opaque bucket. I will keep that in mind. I’ve seen you mention your dislike of Maven in other threads. What do you prefer? Gradle?


#9

Yes, very very much prefer gradle. If maven is glass shards sprinkled on poop ice cream (not poop flavored… actual frozen poop)… then gradle is chocolate chips on mint ice cream. So yummy.


#10

Will keep that mental image in mind.


#11

This one’s probably going to go next to Normen’s “It’s 6 fast.” response to JVM performance in my jME-quotes-hall-of-fame. :joy:

I use and love Gradle myself (ok, sometimes it’s irritating when I have to try 6 different ways to do one “simple” thing, but that’s probably largely due to beginner mistakes. Not a simple tool to learn.). I’ve never used Maven before, but I don’t think I’ve heard of anyone disliking it so much. Now you’ve got me curious… what’s wrong with it?


#12

Generally people who don’t like Maven don’t like that it enforces a particular standardized file structure on your project so it doesn’t play as nicely with other solutions. Kind of an all or nothing thing. Some people don’t like that it hides the complexity and specificity of builds. Some people don’t like having to use xml for the pom file. If something goes wrong it can be very difficult to figure out why particularly with it’s integration in certain IDEs like Eclipse.


#13

It’s a crappy tool pretending to be a powerful tool. Once you use gradle for a while you start to realize all of the things maven does very poorly.

And yeah, the whole dogmatic “I need to do this but maven doesn’t seem to let me” “don’t do that” BS gets old after a while.

The one thing maven gave to the world was a standard directory layout and public repositories. All of which gradle nicely supports out of the box.


#14

Gotcha… yes, I like the standardized source structure, and the repositories are AWESOME. 100% of my project’s dependencies are coming from Maven repos, including jME and Lemur. No manual jar management for me!

I remember fighting Ant’s XML build files… that wasn’t much fun, and considering the handful of times I’ve had to resort to non-idiomatic Groovy code inside a Gradle build to accomplish non-standard tasks like making an executable jar in the distribution root and including all dependent jars in lib/ (no, really Gradle, please just do that, pretty please with a cherry on top), having a full-blown scripting language available in build files seems like kind of a must. At least Gradle gives you plenty of power when you insist on breaking away from conventions. After using Gradle, I think I’m spoiled. :slight_smile:

I especially learned to appreciate Gradle when I started working with DotNet Core and the Nuget package system at work. Gradle + Maven repos are 100x better than those. Literally.


#15

Yeah, at work (where we use maven, boo) I have a gradle build file that I use just for little snippets of utility code like dumping the upside down module dependencies in my poms or collecting a nicely formatted list of to-do comments and so on. So simple to just add a fileTree().each{} inside some task.

But even aside from all of that, gradle is just a better build tool from the ground up. It knows about the whole multiproject structure (maven doesn’t) and has real source/target up-to-date checks and so on. In fact, it’s smarter than I am because I once tried to add a space to a .java file to get a jar to rebuild and gradle was smarter than that. The .class files didn’t change content so the jar wasn’t rebuilt.