collecting snippets of bgolus’ sage advice from other shadowcaster threads, I’ve bodged one of my own, but no dice. It still seems to render the depth fragments as full solid. I am 100% certain that I’m missing something, but with so little thorough documentation on custom passes and what is expected of them, I’m still not certain what I’m even aiming to output from the shadowcaster. All examples I’ve found declare a float4 vertex shader, but then output a scalar 0 after doing pretty ordinary conversions in the vertex shader. Full current code, with obviously lots of trial-and-error commentary and discontinued approaches:
Shader "Custom/Dissolve"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
//Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
Tags { "RenderType"="Opaque" }
//Blend srcAlpha oneMinusSrcAlpha
LOD 200
//ZWrite On
//Alphatest Greater 0
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
//#pragma surface surf Standard fullforwardshadows
//#pragma surface surf Standard addshadow alpha alphatest:_AlphaCut
//#pragma surface surf Standard alpha alphatest:_AlphaCut
#pragma surface surf Standard fullforwardshadows addshadow
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float2 uv_MainTex;
float4 screenPos;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
//float4 _ScreenParams;
// https://en.wikipedia.org/wiki/Ordered_dithering
// static const uint BAYER[8][8] = {
// { 0, 32, 8, 40, 2, 34, 10, 42 },
// { 48, 16, 56, 24, 50, 18, 58, 26 },
// { 12, 44, 4, 36, 14, 46, 6, 38 },
// { 60, 28, 52, 20, 62, 30, 54, 22 },
// { 3, 35, 11, 43, 1, 33, 9, 41 },
// { 51, 19, 59, 27, 49, 17, 57, 25 },
// { 15, 47, 7, 39, 13, 45, 5, 37 },
// { 63, 31, 55, 23, 61, 29, 53, 21 }
// };
static const uint BAYER[64] = {
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)
void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
//https://discussions.unity.com/t/generate-random-float-between-0-and-1-in-shader/728060/8
float2 screenUV = IN.screenPos.xy / IN.screenPos.w;
float2 screenCoord = screenUV * _ScreenParams.xy; // results should be identical to the ShaderToy fragcoord
int bx = round(screenCoord.x)%8;
int by = round(screenCoord.y)%8;
//int bayer = BAYER[by][bx];
int bayer = BAYER[by*8+bx];
//o.Alpha = (c.a*64)>bayer ? 1 : 0;
clip(c.a*64-bayer);
}
ENDCG
// https://discussions.unity.com/t/custom-shadowcaster-for-indirect-surface-shader/808795/2
// https://discussions.unity.com/t/how-to-get-position-of-current-pixel-in-screen-space-in-framgment-shader-function/524186/2
// https://github.com/przemyslawzaworski/Unity3D-CG-programming/blob/master/shadowcaster.shader
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
CGPROGRAM
#pragma vertex vertShadowCaster
#pragma fragment fragShadowCaster
#include "UnityCG.cginc"
StructuredBuffer<float4x4> obj2world;
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
static const uint BAYER[64] = {
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
v2f vertShadowCaster(appdata_base v, uint i : SV_InstanceID)
{
v2f o;
v.vertex = mul(obj2world[i], v.vertex);
o.vertex = mul(UNITY_MATRIX_VP, v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.screenPos = ComputeScreenPos(o.vertex);
// the third link above seems to be running its own trig dither
// and just offsetting the vertex by the result, omitting
// the fragment shader entirely. Trying to eject the geo
// from clip space as a way to make it not render feels dirty...
//vertex.xyz-=(sin(_Time.g)*0.5+0.5)*normal*hash(float(id));
//return UnityObjectToClipPos(vertex);
return o;
}
float4 fragShadowCaster(v2f i) : SV_Target
{
//return 0;
fixed4 c = tex2D (_MainTex, i.uv) * _Color;
float2 screenUV = i.screenPos.xy / i.screenPos.w;
float2 screenCoord = screenUV * _ScreenParams.xy;
int bx = round(screenCoord.x)%8;
int by = round(screenCoord.y)%8;
//int bayer = BAYER[by][bx];
int bayer = BAYER[by*8+bx];
//o.Alpha = (c.a*64)>bayer ? 1 : 0;
clip(c.a*64-bayer);
//return 0; // still not sure I understand how shadowcasters work when they all return 0...
SHADOW_CASTER_FRAGMENT(i);
}
ENDCG
}
}
//FallBack "Diffuse" // keep backup renderers from providing solid shadows
//Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"
}
Once I’m even confident in what I’m trying to output, there’s obviously some independent optimization which could be done of how I generate the values, but for now I’d love to understand how the shadowcaster even leads to the depth render, since at no point do any examples I see seem to even be processing distance/depth on a per-fragment basis…