• Unity
  • Sprite shader depth write

Related Discussions
...

I'm making use of the "Spine/Sprites/xxx" shader to allow for depth of field post-processing effects to work on my animated sprites.

I was wondering if you had a some info somewhere about how the "write to depth" is acheived such that it writes to the camera depth texture, while still showing the nice transparent smooth alpha sprite. Is it using replaement shaders to replace the in-built unity cameraDepthTexture shader?

Is it possible to leverage this in my own custom sprite shaders for use on regular sprites that aren't making use of SkeletonRenderer? I'd love some advice about this, since you've already solved a problem I've been struggling with for months, namely, how to render smooth transparent sprites while writing a rougher cutout to the camera depth texture.

TL/DR: How do i utilise the CameraDepthTexture replacement shader from Spine in my own custom shaders?

Have you tried creating a copy of the CameraDepthTexture shader and adding your required parts to it? Then you would need to call camera.RenderWithShader() with your respective shader.

At the end you could copy and adapt the part

SubShader {
   Tags { "RenderType"="Sprite" } 

to add your own custom type like

SubShader {
   Tags { "RenderType"="MyCustomSprite" } 

Be sure to have the corresponding line clip( alpha - _Cutoff ); in the fragment shader as well to get the cutout effect at the depth buffer. Also be sure to name the parameters like they are in your original shader.

Thanks for the info. I noticed that when I use one of the spine "Sprites/XXX" shaders, I can toggle on depth write and it writes to depth, without having to call

camera.RenderWithShader()

anywhere. This is the case even when i use the material on a simple sprite renderer with no spine components attached. Am I missing something? How is this acheived without the camera code in place?

Another thing I noticed when testing the above is that when depth write is toggled on, the sprite starts to look jagged again, following the depth alpha cutoff value, is this expected behaviour? To me it looks the same as simply changing the render type to "cutout" using the standard shader, but I thought the purpose of this replacement was to visually render the soft edges as with a transparent shader, but also to render the cutout sprite to the depth texture for screen-space post processing.

My apologies if these questions are a little uninformed, i'm very much not a graphics programmer. I'm fine with the csharp side of things but I'm not so great with shaders.

Have you tried enabling Write to Depth and setting Depth Alpha Cutoff to 0.0001? This results in nice blended results with no jagged borders (because the cutoff is set to "only discard when alpha <= 0.0001") while still rendering the whole sprite to the depth buffer:


Magnified view of the Hero character. Enabled depth write provides the correct depth value for the camera blur effect.


[Edit:]
Note however that when you use a blur effect and have multiple sprites layered behind each other, then by design you will have problems in non-cut-off areaswhen setting the cutoff threshold to 0.0001 - then a nicely alpha-blended 95% transparent black pixel will receive 95% of the background color, and thus the background pixel will be perfectly sharp (non-blurred) when the character is in focus, where it should be blurry instead.

Some background pixels around the border wrote to character's depth since they were not discarded at 5% opacity - hence they are not blurry but as sharp as the character.

In this case you cannot handle this in a single render pass - that's where you need the two different alpha cutoff thresholds:
1) one that is low enough to not discard the transparent pixel in the first pass, and then
2) another one at e.g. 0.5 that blurs everything that is mostly transparent and therefore shall count as background.
This case is where the camera.RenderWithShader() replacement shaders come in handy, since they can render another pass just to write different depth values.

Thanksyou for the detailed reply Harald. I'm the lone programmer on our team so I frequenctly have to bounce between areas of focus for particular deadlines, which means sometimes I can't quickly go back and test your advice, but I'll let you know how I get on when i get back to that problem. Really appreciate you taking the time to answer.

You're welcome, hope it helps! No need to hurry at all.

2 个月 后

Hello! Glad I found this thread 🙂 Wanting to do the same thing - get depth info for our spine objects so that we can use depth of field effects. However, when I try toggling on "Write to Depth" on a Spine/Sprite/Unlit shader, I get the following weirdness:

https://www.dropbox.com/s/hq4putsjdionnih/depth%20write%20issue.gif?dl=0

Is it because all of the skeleton's sprites are in the same z-space, so they're just all clipping? Maybe that's not the case, just a hunch! Happy to provide more details, but figured I'd just start there. Thanks!

Hello! 🙂
You can set Z Spacing in the inspector of the SkeletonAnimation component, under the Advanced section.

:bigeyed: just like that huh! Thanks!

You're welcome 8)

2 个月 后

hey , )

is it possible to add " Write to Depth" to the skeleton shader ?

It is possible, however the non-sprite shaders are kept simple on purpose - if we add too many things we end up at the Spine/Sprite/ shaders.
Is there a reason you don't want to use any of the Spine/Sprite/ shaders which provide this?

5 天 后

hey @[已注销]

yes, the reason was, that my spine is rotating if the game object was > to an angle, but using the shader pixel vertex was strange,
skeleton shader worked perfectly but not good with the unity depth of field.. well

I was using

"transform.localEulerAngles = new Vector3(0, 180, 0);" to make a mirror,

but I thing I fix it using :

transform.localScale = new Vector3(-1, 1, 1);

sorry, thx

Bekko :

yes, the reason was, that my spine is rotating if the game object was > to an angle, but using the shader pixel vertex was strange

I fear I don't quite understand the above sentence.

Anyway, you could copy the existing Spine-SkeletonLit.shader shader file and modify the lines

// change this line to give it a new unique name: Shader "Spine/Skeleton Lit" {
// e.g. to this name:
Shader "Spine/Skeleton Lit Depth Write" {

and
either

  1. // change  ZWrite Off to
    ZWrite On
    

    or

  2. // below [Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Compare", Float) = 0.0 // Disabled stencil test by default
    // add the line:
    _ZWrite ("Depth Write", Float) = 1.0
    
    // and change ZWrite Off to
    ZWrite [_ZWrite]
    

Then you can assign your new Spine/Skeleton Lit Depth Write shader as usual.

thx

2 年 后

Unity 5 Sprite Shader with Depth Writing
gistfile1.txt
Shader "Sprites/DefaultWithDepth"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
}

SubShader
{
	Tags
	{ 
		"Queue"="AlphaTest" 
		"IgnoreProjector"="True" 
		"RenderType"="Transparent" 
		"PreviewType"="Plane"
		"CanUseSpriteAtlas"="True"
	}

	Cull Off
	Lighting Off
	Blend One OneMinusSrcAlpha

	Pass
	{
	CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma multi_compile _ PIXELSNAP_ON
		#include "UnityCG.cginc"
		
		struct appdata_t
		{
			float4 vertex   : POSITION;
			float4 color    : COLOR;
			float2 texcoord : TEXCOORD0;
		};

		struct v2f
		{
			float4 vertex   : SV_POSITION;
			fixed4 color    : COLOR;
			half2 texcoord  : TEXCOORD0;
		};
		
		fixed4 _Color;

		v2f vert(appdata_t IN)
		{
			v2f OUT;
			OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
			OUT.texcoord = IN.texcoord;
			OUT.color = IN.color * _Color;
			#ifdef PIXELSNAP_ON
			OUT.vertex = UnityPixelSnap (OUT.vertex);
			#endif

			return OUT;
		}

		sampler2D _MainTex;

		fixed4 frag(v2f IN) : SV_Target
		{
			fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
			c.rgb *= c.a;
			return c;
		}
	ENDCG
	}

	UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
}

}

Thanks for sharing your code. Please note that

[code]

[/code] tags can be used to format code nicely.

1 年 后

Hello! Had a question as it's not really clear for me just yet...
To render to the _CameraDepthTexture (where currently all "ShadowCaster pass" enabled Opaque and AlphaTest shaders are drawn) I put this Camera.RenderWithShader exactly where? on PreRender() of a Camera component script callback?

Looking through the files there's this:

 
Shader "Hidden/Sprite-CameraDepthTexture" {
// Use this shader to render a Depth texture for a camera with soft edged Sprites (using camera.RenderWithShader with replacement tag "RenderType")
// Note the depth is encoded into the pixels RGB not the full RGBA (alpha is needed for blending)

Which I can use as a starting point and not as is since I would rather have the Depth be just default grayscale depth (i.e. no RGB encoding) and clip the pixels with a custom shader but I haven't found a clear rule of thumb way to inject the spine objects into the currently ongoing _CameraDepthTexture target.

Two ways to go about it:

  • Duplicate the spine characters (or set a double material on their mesh renderers, one with an alpha test render queue and the other with the normal alpha blended transparent queue values). Cumbersome.
  • Camera.RenderWithShader with the proper tags (but not quite clear on the instructions)