- Изменено
Edit shader to work with another asset
I'm currently trying to implement a lighting asset that does occlusion and dynamic lighting, but I can't get it to occlude my skeletons as I need to apply a specific shader to the skeleton to render if within the lighting field of view, or occlude if not.
I have 0 shader skills, and I did my best to move the occlusion pass into the skeleton tint shader, but it does not achieve the desired effect. Instead, if occluded they render normally, but if within the light, all frames are being rendered, regardless of the skin applied. It's very odd, but probably makes complete sense to someone who understands shaders.
I'm hoping someone here can help combine the shaders? I believe that's all that's needed... I hope. I've attached both shaders.
Thanks!
Lighting Occlusion Shader
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "2D Dynamic Lights/Masks/Occluded"
{
Properties
{
[PerRendererData] _MainTex ( "Sprite Texture", 2D ) = "white" {}
_Color ( "Shadowed Tint", Color ) = ( 1, 1, 1, 1 )
// [MaterialToggle] PixelSnap ( "Pixel snap", Float ) = 0
_OccludedColor ( "Lit Tint", Color ) = ( 0, 0, 0, 0.5 )
}
CGINCLUDE
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;
sampler2D _MainTex;
v2f vert( appdata_t IN )
{
v2f OUT;
OUT.vertex = UnityObjectToClipPos( IN.vertex );
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
//OUT.vertex = UnityPixelSnap( OUT.vertex );
#endif
return OUT;
}
ENDCG
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha
Pass
{
Stencil
{
Ref 4
Comp NotEqual
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// #pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
fixed4 frag( v2f IN ) : SV_Target
{
fixed4 c = tex2D( _MainTex, IN.texcoord ) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
Pass
{
Stencil
{
Ref 4
Comp Equal
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
fixed4 _OccludedColor;
fixed4 frag( v2f IN ) : SV_Target
{
fixed4 c = tex2D( _MainTex, IN.texcoord );
return _OccludedColor * c * c.a;
}
ENDCG
}
}
}
Spine Skeleton Tint
// Spine/Skeleton Tint
// - Two color tint
// - unlit
// - Premultiplied alpha blending (Optional straight alpha input)
// - No depth, no backface culling, no fog.
Shader "Spine/Skeleton Tint" {
Properties {
_Color ("Tint Color", Color) = (1,1,1,1)
_Black ("Black Point", Color) = (0,0,0,0)
[NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
_Cutoff("Shadow alpha cutoff", Range(0,1)) = 0.1
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
}
SubShader {
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
Fog { Mode Off }
Cull Off
ZWrite Off
Blend One OneMinusSrcAlpha
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}
Pass {
Name "Normal"
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _Color;
float4 _Black;
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
VertexOutput vert (VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
return o;
}
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor) + float4(((1-texColor.rgb) * _Black.rgb * texColor.a[i]_Color.a[/i]i.vertexColor.a), 0);
}
ENDCG
}
Pass {
Name "Caster"
Tags { "LightMode"="ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual
Fog { Mode Off }
Cull Off
Lighting Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Cutoff;
struct VertexOutput {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};
VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) {
VertexOutput o;
o.uvAndAlpha = v.texcoord;
o.uvAndAlpha.a = vertexColor.a;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag (VertexOutput i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a * i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
CustomEditor "SpineShaderWithOutlineGUI"
}
nngafook написалI have 0 shader skills, and I did my best to move the occlusion pass into the skeleton tint shader, but it does not achieve the desired effect. Instead, if occluded they render normally, but if within the light, all frames are being rendered, regardless of the skin applied.
Could you please post your current non-working version of your combined shader? Then we can help you out by pointing out any obvious mistakes.
Sure thing. Here it is. As I said, I just combined the two and made it compile. Best I could do with my lack of knowledge
Shader "Custom/OccludedSkeleton" {
Properties {
_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
[NoScaleOffset] _MainTex ("Main Texture", 2D) = "black" {}
[Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0
[HideInInspector] _StencilRef("Stencil Reference", Float) = 1.0
[HideInInspector][Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp("Stencil Comparison", Float) = 8 // Set to Always as default
// Outline properties are drawn via custom editor.
[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
[HideInInspector] _OutlineReferenceTexWidth("Reference Texture Width", Int) = 1024
[HideInInspector] _ThresholdEnd("Outline Threshold", Range(0,1)) = 0.25
[HideInInspector] _OutlineSmoothness("Outline Smoothness", Range(0,1)) = 1.0
[HideInInspector][MaterialToggle(_USE8NEIGHBOURHOOD_ON)] _Use8Neighbourhood("Sample 8 Neighbours", Float) = 1
[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
_Color ( "Shadowed Tint", Color ) = ( 1, 1, 1, 1 )
_OccludedColor ( "Lit Tint", Color ) = ( 0, 0, 0, 0.5 )
}
CGINCLUDE
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 = UnityObjectToClipPos( IN.vertex );
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color;
#ifdef PIXELSNAP_ON
//OUT.vertex = UnityPixelSnap( OUT.vertex );
#endif
return OUT;
}
ENDCG
SubShader {
Tags {
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas" = "True"
}
Fog { Mode Off }
Cull Off
ZWrite Off
Blend One OneMinusSrcAlpha
Lighting Off
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}
Pass
{
Stencil
{
Ref 4
Comp NotEqual
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// #pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 frag( v2f IN ) : SV_Target
{
fixed4 c = tex2D( _MainTex, IN.texcoord ) * IN.color;
c.rgb *= c.a;
return c;
}
ENDCG
}
Pass
{
Stencil
{
Ref 4
Comp Equal
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
//#pragma multi_compile _ PIXELSNAP_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _OccludedColor;
fixed4 frag( v2f IN ) : SV_Target
{
fixed4 c = tex2D( _MainTex, IN.texcoord );
return _OccludedColor * c * c.a;
}
ENDCG
}
Pass {
Name "Normal"
CGPROGRAM
#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
struct VertexInput {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vertexColor : COLOR;
};
VertexOutput vert (VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.vertexColor = v.vertexColor;
return o;
}
float4 frag (VertexOutput i) : SV_Target {
float4 texColor = tex2D(_MainTex, i.uv);
#if defined(_STRAIGHT_ALPHA_INPUT)
texColor.rgb *= texColor.a;
#endif
return (texColor * i.vertexColor);
}
ENDCG
}
Pass {
Name "Caster"
Tags { "LightMode"="ShadowCaster" }
Offset 1, 1
ZWrite On
ZTest LEqual
Fog { Mode Off }
Cull Off
Lighting Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed _Cutoff;
struct VertexOutput {
V2F_SHADOW_CASTER;
float4 uvAndAlpha : TEXCOORD1;
};
VertexOutput vert (appdata_base v, float4 vertexColor : COLOR) {
VertexOutput o;
o.uvAndAlpha = v.texcoord;
o.uvAndAlpha.a = vertexColor.a;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag (VertexOutput i) : SV_Target {
fixed4 texcol = tex2D(_MainTex, i.uvAndAlpha.xy);
clip(texcol.a * i.uvAndAlpha.a - _Cutoff);
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
}
Harald написалnngafook написалI have 0 shader skills, and I did my best to move the occlusion pass into the skeleton tint shader, but it does not achieve the desired effect. Instead, if occluded they render normally, but if within the light, all frames are being rendered, regardless of the skin applied.
Could you please post your current non-working version of your combined shader? Then we can help you out by pointing out any obvious mistakes.
Any tips Harald?
You need to understand what the Lighting Occlusion Shader
shader does to combine it with the Spine shader, not only concatenate both.
The Lighting Occlusion Shader
relies on the Stencil buffer being setup beforehand with lit
and occluded
pixels, encoded by the stencil value 4
when occluded. The shader basically just needs to do the following:
if (stencil == occludedStencilValue) // occludedStencilValue == 4
renderOccluded
else
renderNormal
Unfortunately you cannot query the stencil value in a shader function, so you need two render passes with the corresponding stencil tests stencil == 4
and stencil != 4
.
If you look at the shader code, it renders in two passes and uses a different stencil test to draw the first normal pass in the condition stencil not equal to 4:
Pass
{
Stencil
{
Ref 4
Comp NotEqual
}
// code to draw the geometry normally follows below
and a second pass for drawing the same mesh in the occluded color:
Pass
{
Stencil
{
Ref 4
Comp Equal
}
// code to draw the geometry with occlusion color overlaid follows below
So what you need to do is:
1) Remove the existing Spine stencil code, as your asset works differently:
Stencil {
Ref[_StencilRef]
Comp[_StencilComp]
Pass Keep
}
2) You just need a duplicated "Normal" pass of the Spine shader:
Pass {
Name "Normal"
one with stencil test for "lit" and one for "occluded", as described above:
Pass
{
Name "Normal"
Stencil
{
Ref 4
Comp NotEqual
}
// add Spine shader code to draw the geometry normally here, copy from Spine shader
}
Pass
{
Name "Normal Occluded"
Stencil
{
Ref 4
Comp Equal
}
// add Spine shader code to draw the geometry with occlusion color overlaid here
}
Harald написалYou need to understand what the
Lighting Occlusion Shader
shader does to combine it with the Spine shader, not only concatenate both.The
Lighting Occlusion Shader
relies on the Stencil buffer being setup beforehand withlit
andoccluded
pixels, encoded by the stencil value4
when occluded. The shader basically just needs to do the following:if (stencil == occludedStencilValue) // occludedStencilValue == 4 renderOccluded else renderNormal
Unfortunately you cannot query the stencil value in a shader function, so you need two render passes with the corresponding stencil tests
stencil == 4
andstencil != 4
.
If you look at the shader code, it renders in two passes and uses a different stencil test to draw the first normal pass in the condition stencil not equal to 4:Pass { Stencil { Ref 4 Comp NotEqual } // code to draw the geometry normally follows below
and a second pass for drawing the same mesh in the occluded color:
Pass { Stencil { Ref 4 Comp Equal } // code to draw the geometry with occlusion color overlaid follows below
So what you need to do is:
1) Remove the existing Spine stencil code, as your asset works differently:Stencil { Ref[_StencilRef] Comp[_StencilComp] Pass Keep }
2) You just need a duplicated "Normal" pass of the Spine shader:
Pass { Name "Normal"
one with stencil test for "lit" and one for "occluded", as described above:
Pass { Name "Normal" Stencil { Ref 4 Comp NotEqual } // add Spine shader code to draw the geometry normally here, copy from Spine shader } Pass { Name "Normal Occluded" Stencil { Ref 4 Comp Equal } // add Spine shader code to draw the geometry with occlusion color overlaid here }
Harald... you are a god. EXCELLENT explanation and guidance. I floundered around a bit and eventually got it working. One thing I missed was adding a second _Color as it was being applied when rendering normally AND occluded.
Thanks so much again. If I knew you in person, and there wasn't a major epidemic going on, I'd buy you a beer.
Cheers!
Thanks very much for your kind words, very glad that it helped! 8) :beer: