To avoid a XY problem, let me first preface my end goal: I need VFX to be rendered around sprites based solely on their Z depth. Both the VFX and the sprites are transparent. In the example below, you can see the sprite always renders on top of it. I can tweak it’s sorting order, but afaik that only controls whether it should always draw in front or always behind. I want the parts of the VFX that are closer to the camera to be rendered on top, and the ones that are behind to be rendered behind. As if the sprite was just a regular 3D model.
Problem example:
Correct behavior example:
From what I understand, this problem only happens cause of transparency. An opaque object like that sphere works just fine. So I’m guessing the solutions lies somewhere in the depth buffer. However, afaik, I can’t control ZWrite and ZTest from VFX Graph, since I can only use Shader Graph as shaders. Is this still possible, then? Cause I tried a lot of combinations and couldn’t get it working.
Any advice would be highly appreciated. Thanks a lot in advance!
There are several ways to achieve this with a sprite in the center:
Without relying on Z-Buffer: Render the fire effect twice, once before the sprite is rendered and once after it (you can use the material render queue to control this for example).
1.a: in the first fire pass, clip all fragments that lie before the sprite (based on distance to camera), and in the second fire pass clip all fragments further away.
1.b: Don’t clip any fragments in either pass, but use the stencil buffer by writing a stencil mask in your wizard sprite shader (discard fragments that are fully transparent) and test against this mask in your second effects pass. Use this one only if you do not wish your wizard sprite to write to the Z-buffer for some reason.
relying on Z-Buffer: Make sure your wizard sprite renders before your fire effect and does write to the Z-Buffer. Discard fragments that have an alpha of 0 (or below some custom threshold value). Your effect already seems to do z-Testing, so you won’t have to make any other changes to the effect.
If your sprite has no semitransparencies (meaning any pixel is either completely opaque or completely transparent), all three approaches should give you artifact free results. If your sprite has anti-aliased edges with semi-transparent alpha values, then only method 1a will give you an artifact-free result, the other two will yield some minor artifacts around the edges of the sprite, though they shouldn’t be too obvious.
Thank you so much! Just tried (2) and it works like a charm. All I did was add
if(col.a <= 0)
discard;
to the fragment shader and it works perfectly. I do get some artifacts, but in play mode it is almost imperceptible. I’ll try your (1a) solution as well, cause I might need transparent gradients for other sprites in the future, who knows.
I couldn’t find anything online, I was already thinking of generating pixel-perfect meshes to render the sprites as opaque hahahah. So thanks a lot for the help, cheers!