Spatials rendering behind other Spatials when they shouldn't

Hello!

Apologies if this has been asked before, I had a brief look but couldn’t find it.

In my game, I have a load of spatials which make up some grass on the ground. I recently optimised them by using GeometryBatchFactory, but now they don’t seem to render properly.

Regardless of whether a spatial is in front or behind the grass, it renders it behind. What have I done wrong here?

Before

After

Thanks for your help!

In what queuebuckets are those geometrys?

Hi Empire Pheonix,

They are renderqueue.bucket.transparent. I thought it best to attach the whole method for creating these grasses:

[java]
public void createLongGrass( Vector3f[] locations)
{
Vector3f[] grassLocations = locations;
Random rand = new Random();
final int noGrasses = 200;
final int squareSize = 200;
final int scaleSize = 3;
ArrayList<Geometry> grassGeomsList = new ArrayList<Geometry>();
Node longGrassNode = new Node();
Node optimizedLongGrassNode = new Node();
Spatial optimizedLongGrassSpatial;

    //For each location to spawn grass in the array of locations:
    for(Vector3f l: grassLocations)
    {
        //Randomly position noGrasses number of grasses.
        for(int i = 0; i &lt;=noGrasses; i++)
        {
            int x = rand.nextInt(squareSize);
            float y = 50;
            int z = rand.nextInt(squareSize);
            int r = rand.nextInt(90);
            int s = rand.nextInt(scaleSize);
            x = x - (x/2);
            z = z - (z/2);

            x = (int) Math.round(l.getX())+x;
            z = (int) Math.round(l.getZ())+z;



            Spatial grass = assetManager.loadModel("Models/Foliage/weeds_1/Weeds 1.j3o");
            Geometry grassGeo = (Geometry) grass;


            try
            {
                
                Material m = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
                
                int randTexture = rand.nextInt(5);
                if(randTexture == 0){m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/weeds_1/weeds_grass_baked_v2.png"));}
                else if(randTexture == 1){m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/weeds_1/weeds_grass_baked_v2 Alt1.png"));}
                else if(randTexture == 2){m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/weeds_1/weeds_grass_baked_v2 Alt 2.png"));}
                else if(randTexture == 3){m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/weeds_1/weeds_grass_baked_v2 Alt 3.png"));}
                else {m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/weeds_1/weeds_grass_baked_v2 Alt 4.png"));}
                
                m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
                m.getAdditionalRenderState().setDepthWrite(false);
                m.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
                grassGeo.setMaterial(m);


            }
            catch(Exception e){e.printStackTrace();}

            
            //Finding Y location
            Vector3f origin = new Vector3f(x, y, z);
            Vector3f direction = new Vector3f(x, -20, z);
            direction.subtractLocal(origin).normalizeLocal();
            Ray ray = new Ray(origin, direction);
            CollisionResults results = new CollisionResults();
            int numCollisions = sceneModel.collideWith(ray, results);
            if (numCollisions &gt; 0) {
                CollisionResult hit = results.getClosestCollision();
                y = y-(hit.getDistance());

            }
            
            //End of Finding Y location
                    
            grassGeo.setQueueBucket(RenderQueue.Bucket.Transparent);
            grassGeo.setLocalTranslation(x, y, z);
            grassGeo.setLocalRotation(new Quaternion(new float[]{0f,(float)r,0f}));
            grassGeo.setLocalScale(s);
            
            longGrassNode.attachChild(grassGeo);

        }
    }
    
   optimizedLongGrassSpatial =  GeometryBatchFactory.optimize(longGrassNode);
   
   optimizedLongGrassNode.attachChild(optimizedLongGrassSpatial);
   worldRootNode.attachChild(optimizedLongGrassNode);
    
}

[/java]

m.getAdditionalRenderState().setDepthWrite(false);

Might create your rendering problem, is there a reason why you did disable it?

Yes, if I don’t disable it, this happens:

…and it doesn’t render the fog when looking through it:

Well, the problem is quite common.

You are mixing up 2 approaches.

With the current blendmode you are still writing depth. But writing only color where alpha!=0

If you want to keep the current blendmode you will have to use the TranslucentBucket and a TranslucentBucketFilter.

Or, instead of BlendMode alpha you keep the default blendmode and use alpha discrard.

DepthWrite needs to be enabled on when using alpha discard however

Thanks for your help everyone!

In the end, I just added in the line: optimizedLongGrassNode.setQueueBucket(RenderQueue.Bucket.Transparent);

I forgot to set the queue bucket on the node where to grass is stored - it works a lot better now! =D

Out of interest, @zzuegg, I am having problems with a different model:

With this tree, it matters a lot more to keep DepthWrite enabled because otherwise the trunk appears weirdly. For this, I am using a TranslucentBucket, but it doesn’t seem to work. It seems to a) not render the fog behind it, b) interfere with its own material only.

[java]
Material m = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

        m.setTexture("ColorMap", assetManager.loadTexture("Models/Foliage/desert_trees/baked_desert_tree_"+r+".png"));
        m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
        m.getAdditionalRenderState().setDepthWrite(true);
        m.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        tree.setMaterial(m);
        
        tree.setQueueBucket(RenderQueue.Bucket.Translucent);

[/java]

Any chance you did not add the TranslucentBucketFilter?

Well, I’m adding it as far as I’m aware. These lines are executed after the trees are created, although it makes no difference to put them before:

[java]
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
TranslucentBucketFilter tbf = new TranslucentBucketFilter(true);
fpp.addFilter(tbf);
fpp.addFilter(createFog());
viewPort.addProcessor(fpp);

[/java]

thats strange, expecially that the grass is rendered over your truck.

Actually since that are all not translucent objects, why not just setting blendmode to color and using alphadiscard?

Sorry, how do I set the alphadiscard?

All of your transparent pixels (even alpha = 0) are writing depth because you haven’t set a discard threshold that I can see. If you fix that then you won’t even need the translucent bucket (which isn’t really a solution for your problem anyway).

@HopelessHyena said: Sorry, how do I set the alphadiscard?

Do you know how to see what uniforms are available for a shader? It could be useful in the future to know this and could also answer your question.

Hi @pspeed,

I didn’t realise it was a value you can set in the shader. I have set values in the past. Anyway, the result of doing so is this:

Where it is better, it still has that very annoying transparency issue around the edges. Obviously, I can increase the threshold to partially eradicate that, but it’s never quite perfect.

My code:

[java]
m.setTexture(“ColorMap”, assetManager.loadTexture(“Models/Foliage/desert_trees/baked_desert_tree_”+r+".png"));
m.setFloat(“AlphaDiscardThreshold”, 0.1f);
m.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
m.getAdditionalRenderState().setDepthWrite(true);
m.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
tree.setMaterial(m);

        tree.setQueueBucket(RenderQueue.Bucket.Transparent);

[/java]

AFAIK the common dirty trick to this is to modify your texture so it will at least draw a green color instead of nothing at the boundaries

There are a few ways to fix this:

  1. create better textures with less soft edges… then the discard threshold can be more effective.
  2. if they already are pretty hard edges then it may be a resolution problem so you could use larger textures so that the alpha doesn’t smear so much.
  3. or the hardest, to create a custom shader (perhaps forked from Lighting) that mixes in a color based on the alpha value after alpha discard threshold is checked.

This is just a common issue with z-sorting and alpha blending. There are no perfect solutions, unfortunately.

... but it's never quite perfect.

Welcome to translucency :wink:

@jmaasing said: Welcome to translucency :wink:

Sounds like a line of Johnny Depp ^^