Flickering with Alpha Textures on a TerrainQuad

Hello,

I’m using textured quads on top of a TerrainQuad and I’d like these textured quads to have translucency (through PNG alpha channel). Everything works fine, my textured quads use the following material:

[java]
Material mat = new Material(game.getAssetManager(), “Common/MatDefs/Light/Lighting.j3md”);
// set DiffuseMap, NormalMap, Shininess
mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

		// both of these are necessary to let shadows cast through transparency
		mat.getAdditionalRenderState().setAlphaTest(true);
		mat.getAdditionalRenderState().setAlphaFallOff(0.8f);

[/java]

Geometry that use this material are later added to the correct bucket:

[java]road.setQueueBucket(Bucket.Transparent);[/java]

And my TerrainQuad uses the following material (two layers of alpha for the two layers of splat textures):

[java]
Material material = new Material(assetManager, “Common/MatDefs/Terrain/TerrainLighting.j3md”);
// red alpha: grass
{
Texture texture = assetManager.loadTexture(“Textures/Terrain/NovaSplat/grass.jpg”);
texture.setWrap(WrapMode.Repeat); // necessary to improve terrain quality
material.setTexture(“DiffuseMap”, // surface color
texture);
material.setFloat(“DiffuseMap_0_scale”, 8f); // doesn’t seem to do anything at the moment
}

	// green alpha: dirt
	{
		Texture texture = assetManager.loadTexture("Textures/Terrain/NovaSplat/dirt.jpg");
		texture.setWrap(WrapMode.Repeat);	// necessary to improve terrain quality
		material.setTexture("DiffuseMap_1", // surface color
				texture);
		material.setFloat("DiffuseMap_1_scale", 8f); // doesn't seem to do anything at the moment
	}

	// do not load normal map for terrain to prevent the error
	// "ERROR: 0:606: error(#202) No matching overloaded function found calculateNormal" in Common/MatDefs/Terrain/TerrainLighting.frag
	material.setFloat("Shininess", 1f); // surface smoothness [1,128]

[/java]

However, I’ve noticed that when I remove and insert the TerrainQuad (to modify it, for example), the alpha textures flicker for a frame before displaying correctly. That is, they flicker like so:

  • (correct, about to add node) ->
  • (incorrect, just added node) ->
  • (correct, about to add node)

As far as I can tell it’s got something to do with:

[java]mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);[/java]

If I disable the blend mode, then there isn’t any flickering at all - but of course, there is then no translucency.

I don’t think it’s got anything to do with the order of (removing, adding) the terrain - if I add the new terrain node before removing the old one, it still flickers. If you look carefully, it almost looks like the background colour (black) is seeping in through the translucency - so this might be a hack fix.

I’m not sure how the rendering engine works. Are there two passes for calculating translucency values? Is there any way to tell the engine to “skip” rendering a frame to screen so that it can render it correctly on the second pass? Will the recent change (r9768) in reintroducing alphaDiscardThreshold help?

(Sorry about the images, I can’t work out the formatting on this forum.)

Try turning off depth writing for your transparent quads. It’s set on the same object that blend mode is.

Thanks for your quick reply :slight_smile: To the transparent quads I’ve added:

[java]mat.getAdditionalRenderState().setDepthWrite(false);[/java]

However it still flickers. Now the flicker is not textures that are slightly darker, but the textures are no longer being rendered. i.e. there’s a frame of before the scene is rendered correctly.

I tried moving it to the Translucent bucket but that didn’t make a difference. If I turn off BlendMode.Alpha but keep setDepthWrite(false) it still flickers.

This is with jME3_2012-09-11 nightly - could upgrading help? (Worried about other things breaking…)

Is the terrain also in the transparent bucket?

Also, the fact that it is only bad for one frame indicates that this might not be scene graph related but something you update after one frame.

Edit: unless you are moving when it happens.

Yay! Yes, that worked. Putting the terrain into the Transparent bucket stopped the flickering.

[java]
terrain.setMaterial(generateTerrainMaterial( … ));
terrain.setQueueBucket(Bucket.Transparent);
terrain.setShadowMode(ShadowMode.Receive);

		GeometryBatchFactory.optimize(terrain);

[/java]

Now there’s just rendering artifacts at the alpha edges of the textures - but I can probably touch those up with background colour or putting more things in the right buckets/scene. (e.g. in this figure, there’s a red sphere behind the terrain and texture, and it’s showing up in the translucent edges of the texture.) Not a big deal at all.

Actually, it seemed like the only way you could be having the problem was if the terrain was already in the transparent bucket. Otherwise, the quads would have always been drawn after the terrain.

It’s very strange.

z fighting?

I didn’t think about shadows before… now I wonder if it’s related to that after his latest post.

The attached video shows flickering I am getting on my terrain.

I’ve tried combinations of bucket and shadow settings to no effect, so I’m open to suggestions please.

This is the code I use to set up the terrain.

private void createTerrainLightingCraters()
 {
    Random r = new Random();
    int level_of_detail = 8;
    float stepSize = (int)Math.pow(2,level_of_detail) + 1;
    int numpoints = (int) Math.pow(2,level_of_detail) + 1;
    double total_size = stepSize* numpoints;
    float roughness = 0.3f + (float)r.nextFloat()* 0.2f;
    float [] heightMap = new float[numpoints*numpoints];
    float multFactor =  3 + (float)r.nextFloat()* 5f;
    float totalSize = (float)Math.pow(2,8)+1;
    float xScale = stepSize*50, zScale = xScale;

    yScale=stepSize*35;
    double[][] levels ;
    nPoints = numpoints;
    sSize = (int)xScale;
    terrainMin = 999999f;
    terrainMax = -999999f;
   // Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/heightmap.png");

terrainMat = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");
terrainMat.setBoolean("useTriPlanarMapping", false);
terrainMat.setBoolean("WardIso", true);    
   
Texture moon = assetManager.loadTexture("Materials/low.png");
moon.setWrap(WrapMode.Repeat);
terrainMat.setTexture("DiffuseMap", moon);
terrainMat.setFloat("DiffuseMap_0_scale", 32);
Texture normalMap0 = assetManager.loadTexture("Materials/grass_normal.jpg");
normalMap0.setWrap(WrapMode.Repeat);
terrainMat.setTexture("NormalMap", normalMap0);

Texture rock = assetManager.loadTexture("Materials/moon6.png");
rock.setWrap(WrapMode.Repeat);
terrainMat.setTexture("DiffuseMap_1", rock);
terrainMat.setFloat("DiffuseMap_1_scale", 32);
Texture normalMap1 = assetManager.loadTexture("Materials/rock_normal.png");
normalMap1.setWrap(WrapMode.Repeat);
terrainMat.setTexture("NormalMap_1", normalMap1);

Texture snow = assetManager.loadTexture("Materials/snow.png");
snow.setWrap(WrapMode.Repeat);
terrainMat.setTexture("DiffuseMap_2", snow);
terrainMat.setFloat("DiffuseMap_2_scale", 64);
Texture normalMap2 = assetManager.loadTexture("Materials/road_normal.png");
normalMap2.setWrap(WrapMode.Repeat);
terrainMat.setTexture("NormalMap_2", normalMap2);

//..............................
// Create crater terrain
//..............................

levels =  CraterTerrain(level_of_detail);   

   
  //......................................................... 
  // Get the 2D array (levels.terrain) into a one D array
  //.........................................................
 
   int k = 0;
   
   for(int x = 0;x < numpoints; x++)
    {
        for(int y = 0; y <numpoints ;y++)
        {
           heightMap[k] = (float) levels[y][x] * multFactor;
        
           if(heightMap[k] > terrainMax) terrainMax = (float)heightMap[k];
           if(heightMap[k] < terrainMin) terrainMin = (float)heightMap[k]; 
           k++;
        }
    }

/*...............................................
// Create alphamap dependent on height
/................................................*/

CreateAlphaMapLevel(numpoints, levels) ;

// CreateAlphaMapGrad(numpoints, levels) ;

terrainMat.setTexture("AlphaMap", assetManager.loadTexture("Materials/alphamap.png"));
terrain = new TerrainQuad("terrain", 17, numpoints,heightMap);
 
terrain.setLocalTranslation(0f,0f,0f);
terrain.setLocalScale(xScale,yScale,zScale);
terrain.setMaterial(terrainMat);

//..................................
//**Add level of detail control
//..................................

TerrainLodControl lodControl = new TerrainLodControl(terrain, cam);
terrain.addControl(lodControl);
terrain.setQueueBucket(Bucket.Transparent);
terrain.setShadowMode(ShadowMode.Receive);
 //   terrain.setCullHint(CullHint.Dynamic);
//...............................................

// Assign the bases
//...............................................

AttachBases((int)stepSize, numpoints, xScale, yScale, zScale) ;

TerrainPhysics = new RigidBodyControl(0f);
terrain.addControl(TerrainPhysics);
bulletAppState.getPhysicsSpace().add(TerrainPhysics);     

rootNode.attachChild(terrain);
1 Like