• RuntimesUnity
  • about transparency shader in Unity 6 with Spine 4.2.40 use built-in RP

Harald I achive the affect between two model, but not work for leaf in a same tree ( a same skeleton)

Perhaps I misunderstood what quality you want from your cutout effect. A perfect result like with normal transparent overlap is not possible, but you might be happy with a properly setup cutout shader already.

Your original video in the first posting shows a cutout effect with no alpha threshold in place at all, or a very badly adjusted one. So you are likely just missing the alpha-based discard statement. You could have a look at e.g. the Spine/Skeleton Lit ZWrite shader where there is a _Cutoff property, or just use the Spine/Skeleton Lit ZWrite shader right away.

Note that it's not a good idea to use the stencil buffer for depth-based masking, you should just write to the z buffer instead of the stencil buffer. The stencil buffer is normally used for masking and other non-depth-related shader things (shadow volumes, etc).

    Related Discussions
    ...

    Harald screenshot here

    Although it can't be fade in and out, more like cutout, but it's enough for me.

    well, I just wanna ask , Can the perfect feature be achived ? (only show the top transparent pixel)

      suanLoBeach Although it can't be fade in and out, more like cutout, but it's enough for me.

      Unfortunately I don't understand what you mean by that. Why can't you fade in or out? What is the setup in your screenshot, as it shows some semi-transparent parts and a write rectangle.

      Please always describe what you are trying to achieve and what you get instead in as much detail as possible. And when sharing screenshots, please note that we don't know the setup that has led to this screenshot, which objects are placed where (a scene view screenshot helps), which shaders are used where, etc.

      suanLoBeach well, I just wanna ask , Can the perfect feature be achived ? (only show the top transparent pixel)

      I just had a look at the Skeleton Lit ZWrite shader, it does not use a depth-pre-pass to ensure only the topmost triangles show through.

      So you could use the depth pre pass in your shader like from Spine/Outline/OutlineOnly-ZWrite. Add the following pass

      Pass
      {
      	Name "DepthOnly"
      
      	ZWrite On
      	ColorMask 0
      	Cull Off
      
      	CGPROGRAM
      	#pragma vertex DepthOnlyVertex
      	#pragma fragment DepthOnlyFragment
      	#include "CGIncludes/Spine-DepthOnlyPass.cginc"
      	ENDCG
      }

      before

      Pass {
          Name "Normal"

      Otherwise you would need to invert the draw order of your skeleton.

        Harald sorry to foget to post my code, I add these codes into spine/skeleton shader

        // code start
        Shader "Spine/Skeleton_custom" {
        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
        _AlphaClip ("Alpha Clip Threshold", Range(0.001,0.1)) = 0.01 // Alpha clipping threshold
        _AlphaFeathering ("Alpha Feathering", Range(0.001,0.05)) = 0.01 // Controls the feathering range

        	// Outline properties are drawn via custom editor.
        	[HideInInspector] _OutlineWidth("Outline Width", Range(0,8)) = 3.0
        	[HideInInspector][MaterialToggle(_USE_SCREENSPACE_OUTLINE_WIDTH)] _UseScreenSpaceOutlineWidth("Width in Screen Space", Float) = 0
        	[HideInInspector] _OutlineColor("Outline Color", Color) = (1,1,0,1)
        	[HideInInspector][MaterialToggle(_OUTLINE_FILL_INSIDE)]_Fill("Fill", Float) = 0
        	[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] _OutlineOpaqueAlpha("Opaque Alpha", Range(0,1)) = 1.0
        	[HideInInspector] _OutlineMipLevel("Outline Mip Level", Range(0,3)) = 0
        }
        
        SubShader {
        	Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
        
        	Fog { Mode Off }
        	Cull Off
        	Lighting Off
        
        	Stencil {
        		Ref[_StencilRef]
        		Comp[_StencilComp]
        		Pass Keep
        	}
        
        	// Pass 1: Only writes depth, doesn't render color, but uses feathering effect
        	Pass {
        		Name "DepthOnly"
        		ZWrite On
        		ColorMask 0
        		
        		CGPROGRAM
        		#pragma vertex vert
        		#pragma fragment frag
        		#include "UnityCG.cginc"
        		#include "CGIncludes/Spine-Common.cginc"
        		sampler2D _MainTex;
        		float _AlphaClip;
        		float _AlphaFeathering;
        
        		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 = PMAGammaToTargetSpace(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
        			
        			 // Calculate final alpha
        			float finalAlpha = texColor.a * i.vertexColor.a;
        			
        			// Use smooth transition instead of hard clipping
        			float lowerBound = _AlphaClip - _AlphaFeathering;
        			float upperBound = _AlphaClip + _AlphaFeathering;
        			
        			// If alpha is less than lower bound, discard pixel completely
        			if (finalAlpha < lowerBound)
        				discard;
        			
        			// Use smooth transition in boundary area
        			if (finalAlpha < upperBound) {
        				// Calculate attenuation factor - smooth transition in boundary area
        				float t = (finalAlpha - lowerBound) / (2.0 * _AlphaFeathering);
        				float alphaFactor = smoothstep(0.0, 1.0, t);
        				
        				 // Randomly discard some pixels to create feathering effect
        				if (alphaFactor < frac(sin(dot(i.uv, float2(12.9898, 78.233))) * 43758.5453))
        					discard;
        			}
        			
        			return float4(0, 0, 0, 0); // Do not output color
        		}
        		ENDCG
        	}
        
        	// Pass 2: Renders color, but doesn't write to depth
        	Pass {
        		Name "Normal"
        		ZWrite Off
        		Blend One OneMinusSrcAlpha
        		
        		CGPROGRAM
        		#pragma shader_feature _ _STRAIGHT_ALPHA_INPUT
        		#pragma vertex vert
        		#pragma fragment frag
        		#include "UnityCG.cginc"
        		#include "CGIncludes/Spine-Common.cginc"
        		sampler2D _MainTex;
        		float _AlphaClip;
        
        		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 = PMAGammaToTargetSpace(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
        
        			// Keep alpha test consistent
        			float finalAlpha = texColor.a * i.vertexColor.a;
        			clip(finalAlpha - _AlphaClip);
        
        			return (texColor * i.vertexColor);
        		}
        		ENDCG
        	}
        
        	// Caster Pass (unchanged)
        	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"

        }

          Harald I'm migranting my project to Godot, So, I'm waitting Godot4.4 runtime, i'll solve this problem in Godot again.

            suanLoBeach sorry to foget to post my code, I add these codes into spine/skeleton shader

            Thanks for the update. Reading your code and looking at the screenshot again now explains why the border looked as it is, I was wondering if you had some compression artifacts leading to the dot-pattern.

            I wonder why you are using dither-style feathering though, as a standard threshold might look better with typical the image outlines, which are just a gradient alpha. The purpose of dither patterns is usually where a homogenous area needs to become transparent, there you can't solve it with a single tweaked threshold. If you know what you're doing it's fine of couse, you might have your reasons.

            suanLoBeach well, I just wanna ask , Can the perfect feature be achived ? (only show the top transparent pixel)

            Perfect alpha blending showing the same result as a render texture would: no, as I said above multiple times. Otherwise we would have provided it in the example scenes instead of the render texture component.

            suanLoBeach I'm migranting my project to Godot, So, I'm waitting Godot4.4 runtime, i'll solve this problem in Godot again.

            Good luck with the migration. Note however that the problem will not change in the slightest 🙂.

              Harald

              Harald I wonder why you are using dither-style feathering though, as a standard threshold might look better with typical the image outlines, which are just a gradient alpha. The purpose of dither patterns is usually where a homogenous area needs to become transparent, there you can't solve it with a single tweaked threshold. If you know what you're doing it's fine of couse, you might have your reasons.

              Because my texture is made by the ink flow diffusion drawing method, there will be many places with high transparency. If I don't use dither, the top model will have many very transparent areas that block the objects behind. Visually, it looks like it is blocked by air. For example, the trunk of the tree in my screenshot. If I don't use dither, part of the outer side of the trunk will also block the objects behind.

                suanLoBeach If I don't use dither, the top model will have many very transparent areas that block the objects behind.

                Not if you set the _AlphaClip threshold properly to exclude these areas of high transparency. You receive jagged outines instead then, obviously.

                  Harald Can I do that on many texture in a same skeleton ?
                  different mesh, different texture, like those leaf, in the same skeleton

                  Harald How to do it ? the texture have the same Z value, they are on a same plane

                  Harald oh, it's what i need ,thx

                  I have another quastion, I wanna leaf is dynamic by vertex displacement,but stem is static, now they use the same material , so How can I make two different affect, I'll add teh code about vertex displacement into my custom spine shader, but there is only one material slot here, do i need to make two slot in spine and how to make it ?

                    suanLoBeach I'll add teh code about vertex displacement into my custom spine shader, but there is only one material slot here, do i need to make two slot in spine and how to make it ?

                    I'm not sure which Material slot you're talking about, but if you want different materials for different slots, see the SkeletonRendererCustomMaterials component.

                    In general please always check out the spine-unity documentation pages first and the example scenes that come with the spine-unity runtime. For common tasks there is almost always an entry in the documentation or example scene available.

                      Harald So the step of customizing the materials of multiple components is done in Unity? Is there anything I need to do in Spine?

                      Harald I have know how to set custom material for any slot, thanks

                        suanLoBeach Glad to hear you've figured it out, thanks for getting back to us.