Transparent faces not rendering when looking through another transparent face

When I look through a face I cannot see other transparent faces, but they only don’t render when their x pos is greater than the camera’s x pos, here is a video that shows it in action


here is the material for the meshes:
new THREE.MeshLambertMaterial({ map: texture, transparent: true, alphaMap: alphaTexture, vertexColors: THREE.VertexColors })
The general way I make the water and tree, is by creating 2 faces for each side of the block, it’s using a alpha map to make the tree transparent and the water transparent, I tried using alphaTest, but that as expected just removed lower alpha textures, which I use for glass blocks. Is there a way I can get rid of the artifacts?

new THREE.MeshLambertMaterial({ map: texture, transparent: true, alphaMap: alphaTexture, alphaTest:0.5,vertexColors: THREE.VertexColors })

1 Like

Thanks, but that did not work, instead it stopped the water from disappearing, but now the alpha values are being changed, and my glass is not rendering since it’s alpha is lower than 0.5, something you might need to know is that some of the leaf texture is half-transparent

1 Like

For this use case, I would use the famous screendoor transparency trick used in many video games.
A visual trick to dodge complex depth sorting and transparency clipping.
Because three.js is not an engine, and doesn’t include such advanced optimisation (yet? :wink:)

https://gkjohnson.github.io/threejs-sandbox/screendoor-transparency/

Another amazing piece of code by gkjohnson. Nothing stop this man!

2 Likes

thank you! :smile: How would I go about adding this into my game?
(the faces are using uvs from a texture, and alpha is defined from a alpha map image)

For tree without transparent:
new THREE.MeshLambertMaterial({ map: texture, transparent: false, alphaMap: alphaTexture, alphaTest:0.5,vertexColors: THREE.VertexColors })

1 Like

I fear you may have dive into the realm of three.js custom shaders.
then combine your alphaMap uniform with the ditherTex

If you don’t want to bother with it, follow @Chaser_Code advice.
Sometimes it’s better to just remove transparency and only use alphaTest

I’m using the method from Oxyn, but when trying to set alpha values in a shaderMaterial, the effect does not work, (I’m getting black instead of invisible pixels on the texture) how do I use this idea for a shaderMaterial?

→ Nvm, I just figured out I can use discard in the shader code to not render a pixel

I forgot to mention it doesn’t provide a perfect answer for transparency (hope i didn’t oversold it) but still a way to mitigate the most annoying issues without rewriting three’s renderer completely.
more information about the limitation here:

yea ok, sounds great, well thanks for this solution :smile:

I suspect people may still struggle with it
because it’s an old depreciated example with some shenanigans not used anymore.

So here is a github repo + live demo link using three r153 and very simplified code.

There is many others cool tricks about dithering/screendoor.
But I can’t really spend more time on this. :pensive:

1 Like

Thank you for this :smile:, I’m currently figuring out how to convert the glsl code into one big string so that I can understand it properly, but it works exactly how I need it to.

1 Like

I’ve put it in my game, but the colours of the transparent meshes are not merging with each other, this can cause a effect where faces do not render when behind another mesh, here is an example:


Is there anyway I could make the faces render even if their covered by another transparent face?

The dither shader should never be transparent.
If you mix dither with transparency or among other transparent shaders, you may get classic clipping issues again. The culprit is always transparent:true and there is no way to avoid this as long it’s used.

I posted another way here. Results are impressive, it remove sorting so no clipping, while keeping good performance. But take note it’s pretty advanced (this is Unreal engine level stuff) , a hit or miss with little ways to tweak it unless you an expert in this field (wich I’m absolutely not :smiling_face_with_tear:)

transparent is not on, here, this is my material:

new THREE.ShaderMaterial({
		  vertexShader: vertexShader,
		  fragmentShader: fragmentShader,
			transparent: false,
			vertexColors: THREE.VertexColors,
		  uniforms: {
		    texture2: { value: texture },
		    alpha: { value: alphaTexture },
				cameraPos: { value: camera.position },
		  },
		})

and here is the fragment shader:

uniform sampler2D texture2;
	uniform sampler2D alpha;
 	varying vec3 vWorldPosition;
	varying vec2 vUv;
	varying vec3 vColor;
	uniform vec3 cameraPos;
 	float tanh(float x) {
  	return (exp(2.0 * x) - 1.0) / (exp(2.0 * x) + 1.0);
	}
	float bayerDither2x2( vec2 v ) {
		return mod( 3.0 * v.y + 2.0 * v.x, 4.0 );
	}
	float bayerDither4x4( vec2 v ) {
		vec2 P1 = mod( v, 2.0 );
		vec2 P2 = mod( floor( 0.5  * v ), 2.0 );
		return 4.0 * bayerDither2x2( P1 ) + bayerDither2x2( P2 );
	}
	void main() {
 		float distance2 =	distance(vWorldPosition, vec3(0.0, 0.0, 0.0));
		// distance2 = tanh(distance2);
		// if (distance2 > 0.9) {
		// 	distance2 = 0.9;
		// }
		// distance2 /= 2.0;
		// distance2 = 1.0-distance2;
		float alpha2 = texture2D( alpha, vUv).r;
		// if( texture2D( texture2, gl_FragCoord.xy).r > alpha2 ) discard;
		if( ( bayerDither4x4( floor( mod( gl_FragCoord.xy, 4.0 ) ) ) ) / 16.0 >= alpha2 ) discard;
		vec4 tc = texture2D( texture2, vUv);
		gl_FragColor = vec4(tc.r*vColor.r, tc.g*vColor.g, tc.b*vColor.b, 1.0);
	}

I don’t really know shaders that well since I started using them 2 days ago, do you know what’s causing the clipping?
(btw ignore the weird distance stuff)

The shader looks fine, however I would optimize the way your large volumes of water behave. Seem you draw the 6 faces of each singles water cubes. That’s kind of overkill.

Most games remove the mesh when camera is underwater, and apply a “blue” filter on the whole screen, removing any need for transparency. When you need to display pockets of air, you draw only the pocket, not the whole ocean’s mesh.

This way you could mitigate the limitations of dither shaders, they cannot handle infinite depth and won’t draw too many overlapping shapes.

I have done that, the faces that are rendering there are the edges of the water mass, this is because there’s a cave there and I don’t have water physics yet. I’ll try messing around with the demo to see if it has the same issue.

gkjohnson’s demo has this issue, this is perfectly normal tho.
At some point three.js renderer remove whole mesh who are not supposed to be visible. Opaque or transparent doesn’t matter at this point (the dither trick become useless) the renderer’s code will prevail.