GPU Instancing and depth problem

Hi! I am trying to create GPU instanced particles (no unity particle system involved). Currently I just have a bunch of quads with a texture and I move around in a compute shader. The problem is with transparency. It seems to me that some instances are rendered in wrong order and I think the issue might be in z depth. I tried to play around with writing to depth buffer in frag shader, but it didn’t really help. Below are the screenshots of what is happening and the shader code. If anyone has any idea what is the problem and how to fix it, I would really appreciate it. Thanks!

CODE:

StructuredBuffer _ParticlesData;
StructuredBuffer _VertexPositions;
StructuredBuffer _Triangles;
StructuredBuffer _UV;

v2f vert (uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID)
{
int realVertexId = _Triangles[vertex_id];
float4 worldCoord = float4(_ParticlesData[instance_id].Position, 1);
float4 position = float4(_VertexPositions[realVertexId] + _ParticlesData[instance_id].Position, 1);
float4 viewPos = mul(UNITY_MATRIX_V, worldCoord) + float4(_VertexPositions[realVertexId], 0);
float4 outPos = mul(UNITY_MATRIX_P, viewPos);

v2f o;
o.ClipSpacePosition = outPos;
o.data.x = length(position) / 10;
o.uv = _UV[realVertexId];
return o;
}

fixed4 frag (v2f result) : SV_Target
{
float alpha = tex2D(_MainTex, result.uv).a;
float4 color = float4(_Color.rgb, alpha);
return color;
}

8813311--1199206--upload_2023-2-17_13-18-37.png

Most particles use additive blending, so it does not matter what order they are rendered in. In the Pass {} block, of your vertex/fragment shader, put Blend One One.

For certain types of particles, you may need to use different blend modes (eg alpha testing might be appropriate for falling leaves).

1 Like

If it is not specified, Unity shaders default to ZWrite On. For transparent materials, usually you want ZWrite Off. ZWrite along with ZTest is used for depth sorting of opaque objects, but it is only really useful for opaque objects because the depth buffer can only store one depth value per pixel. For transparent objects you want set turn ZWrite Off and then you’ll either need to use a blend mode that doesn’t care about the render order, like additive (though I’d recommend Blend SrcAlpha One instead of Blend One One), or you’ll need to manually sort the particles in back to front order in the structured buffers.

1 Like

Yeah, z testing was on, and after I disabled it things changed but not much better. Now, if I look at the particles with cameraZ being negative I - they render properly. But, when cameraZ is positive at certain distances I get the black square artifacts again.


This is a screenshot with cameraZ positive at distance when rendering is ok.


And this same position, but a little further away from the center - artifacts appear again. Plus, particles behind the blue plane are now occluded by it - which is what I expect always, but it only happens when the artifacts appear.

In my shader code I have:
Tags{ “RenderType” = “Transparent”
“Queue” = “Transparent”}
LOD 200

Blend SrcAlpha One
ZTest Off

You do not want ZTest Off, you want that on, or more specifically ZWrite GEqual, which is the default if you don’t include it… You want ZWrite Off.

ZTest Off will mean it will render on top of opaque objects, even if they’re behind those surfaces.

ZWrite Off means it won’t write to the depth buffer (aka z buffer), which is still what’s causing your issue

The behavior of the black squares showing or not is due to the render order changing. In the first image the walls are rendering first, and then the particles. In the second image the particles were rendering first, and then the walls. Because ZWrite was still enabled, in the second image the walls aren’t rendering anywhere they’re behind the particles because that’s what the depth buffer along with ZWrite and ZTest are supposed to do to ensure depth sorting.

However the fact the order between the walls and the particles isn’t consistent makes me think the Render Queue on the material itself is overriding the shader (make sure it’s set to 3000 or Use Shader and not 2000 or some other number), or you’re manually rendering the mesh during the opaque queue.