Visual artifacts when using cull_disabled and transparency

Godot Version

4.2

Question

I have visual artifacts when attempting to render transparent objects with cull_disabled

Here is the simple shader I made to illustrate it the problem in the above image:

shader_type spatial;
render_mode cull_disabled, depth_draw_always;

void fragment() {
	ALBEDO = FRONT_FACING ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
	ALPHA = 0.5;
}

It still happens when using the same color on both front and back faces but is less obvious. Am I just going about this the wrong way entirely? If want to make a material for empty bottle where you can also see the back side, how should I be going about it instead?

I don’t have a good solution, but I have an explanation from the godotengine github.
“This is a limitation of how transparency works. Transparent meshes are sorted then drawn by their distance from the camera, but within each mesh, faces are drawn in an arbitrary order, not sorted. So you can’t guarantee that the faces on the far side of the mesh will be drawn before the faces on the close side of the mesh. I believe it’s based on the order of the vertices/faces in the mesh’s arrays, but I haven’t looked at the actual implementation.” - @tetrapod00 on github

Transparent object with no culling creates visual artifacts #97895

Just to follow up on this, after a lengthy discussion in the Godot Cafe Discord
The approaches that were tried are as follows:

  1. Create a material with two passes. For the first pass, cull the front face with rendering_priority = 0. For the second pass, cull the front face with rendering_priority = 1. This looks correct, but will be drawn over any other transparent objects in the scene.

  2. use blend_mode add. This doesn’t look correct and will continually brighten the scene.

  3. Split the front and back faces into two meshes and use a vertex shader to move the front face closer to the camera. This doesn’t change the rendering order, so it causes flickering.

  4. Split the front and back faces into two meshes and every frame ensure the front face is a little closer to the camera by moving the Node. This is cumbersome and requires some perspective shifts, but should provide the desired result.

I figured it out. Here is the solution:

Create two meshes with different materials. The first mesh should be the back and should have Cull set to Front. The second mesh should be the front and should have Cull set to Back, it should also have VisualInstance3D.sorting_offset set to a small positive value.

This causes the renderer to render all of the back mesh before all of the front mesh is rendered.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.