unity-shader半透明物体Transparent 和 AlphaTest的产生阴影和接收阴影

本文详细解析了Unity中使用Shader实现半透明(Transparent)和AlphaTest物体的阴影投射与接收机制。包括如何通过Unlit/shadowCast_Transparent和Unlit/shadowCast_AlphaTestShader定义,实现不同透明度物体的阴影效果,以及光照模型的计算过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)关于Transparent半透明物体产生的阴影,特别注意半透明物体接受的阴影(不常用)
在这里插入图片描述
(2)关于AlphaTest物体产生阴影和接受阴影:(接受阴影的地方透明了,看不到阴影了)
在这里插入图片描述
Transparent物体的shader:

Shader "Unlit/shadowCast_Transparent"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _AlphaScale("AlphaScale",Range(0,1))=0.5
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="AlphaTest+50" "IgnorProjector"="True"}
        LOD 100

        Pass
        {
            ZWrite off
            Blend SrcAlpha OneMinusSrcAlpha
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag


            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;                
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                SHADOW_COORDS(1)
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _AlphaScale;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                TRANSFER_SHADOW(o);
                return o;
            }TRANSFER_SHADOW(o)

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                float shadow = SHADOW_ATTENUATION(i);
                col.a = col.a - _AlphaScale;
                col.rgb = col.rgb * shadow; 
                return col;
            }
            ENDCG
        }
    }
    Fallback "Diffuse"
}

(2)AlphaTest的shader:

Shader "Unlit/shadowCast_AlphaTest"
{
    Properties
    {
        _MainTex("MainTex",2D)="white"{}
		_Color("Diffuse",Color) = (1,1,1,1)
		_Specular("Specular", Color) = (1,1,1,1)
		_Gloss("Gloss", Range(8.0, 256)) = 20
        _Cutoff("alphaTest Cutoff value",Range(0,1))=0.2
    }
    SubShader
    {
        Tags { "RenderType" = "TransparentCutout" "Queue"="AlphaTest" }
		LOD 100
		Pass
		{
			Tags{"LightMode" = "ForwardBase"}
			CGPROGRAM
			#pragma multi_compile_fwdbase
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"

			fixed4 _Color;
			fixed4 _Specular;
			float _Gloss;
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Cutoff;
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
				float3 normal:NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float3 vertexLight : TEXCOORD2;
				SHADOW_COORDS(3) //仅仅是阴影
                float2 uv : TEXCOORD4;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				//仅仅是阴影
				TRANSFER_SHADOW(o);
                o.uv = TRANSFORM_TEX(v.uv,_MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed3 worldNormal = normalize(i.worldNormal);
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

                float4 cli = tex2D(_MainTex,i.uv);
                clip(cli.a - _Cutoff);

				fixed3 diffuse = cli.rgb* _LightColor0.rgb * _Color.rgb * max(0, dot(worldNormal,worldLightDir));

				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 halfDir = normalize(worldLightDir + viewDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0,dot(worldNormal,halfDir)),_Gloss);

				fixed shadow = SHADOW_ATTENUATION(i);

				//这个函数计算包含了光照衰减已经阴影,因为ForwardBase逐像素光源一般是方向光,衰减为1,atten在这里实际是阴影值
				//UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                return fixed4((ambient + (diffuse + specular) * shadow + i.vertexLight), 1);
            }
            ENDCG
        }
    }
    Fallback "Transparent/Cutout/VertexLit"
}

<think>我们正在讨论UnityShader中的透明度设置。根据引用内容,Unity中有两种主要的透明度处理方式:透明度测试透明度混合。透明度测试(AlphaTest):-使用一个阈值(_Cutoff),当片元的透明度小于该阈值时完全丢弃,大于等于则完全保留。没有半透明效果。-需要在SubShader标签中设置:Tags{"Queue"="AlphaTest""RenderType"="TransparentCutout""IgnoreProjector"="True"}透明度混合(AlphaBlending):-允许半透明效果,将当前片元颜色与颜色缓冲区中的颜色进行混合。-需要设置混合模式,如:BlendSrcAlphaOneMinusSrcAlpha-标签设置:Tags{"Queue"="Transparent""RenderType"="Transparent""IgnoreProjector"="True"}现在,我将提供一个简单的教程,展示如何编写一个包含透明度测试透明度混合的Shader。###透明度测试Shader示例```glslShader"Custom/AlphaTest"{Properties{_MainTex("Texture",2D)="white"{}_Cutoff("AlphaCutoff",Range(0,1))=0.5}SubShader{Tags{"Queue"="AlphaTest""RenderType"="TransparentCutout""IgnoreProjector"="True"}Pass{CGPROGRAM#pragmavertexvert#pragmafragmentfrag#include"UnityCG.cginc"structappdata{float4vertex:POSITION;float2uv:TEXCOORD0;};structv2f{float2uv:TEXCOORD0;float4vertex:SV_POSITION;};sampler2D_MainTex;float4_MainTex_ST;float_Cutoff;v2fvert(appdatav){v2fo;o.vertex=UnityObjectToClipPos(v.vertex);o.uv=TRANSFORM_TEX(v.uv,_MainTex);returno;}fixed4frag(v2fi):SV_Target{fixed4col=tex2D(_MainTex,i.uv);//透明度测试:若透明度小于阈值则丢弃片元clip(col.a-_Cutoff);returncol;}ENDCG}}FallBack"Diffuse"}```###透明度混合Shader示例```glslShader"Custom/AlphaBlend"{Properties{_MainTex("Texture",2D)="white"{}_Color("ColorTint",Color)=(1,1,1,1)}SubShader{Tags{"Queue"="Transparent""RenderType"="Transparent""IgnoreProjector"="True"}//关闭深度写入,避免半透明物体相互遮挡问题ZWriteOff//设置混合模式:源因子为SrcAlpha,目标因子为OneMinusSrcAlpha(即传统透明度混合)BlendSrcAlphaOneMinusSrcAlphaPass{CGPROGRAM#pragmavertexvert#pragmafragmentfrag#include"UnityCG.cginc"structappdata{float4vertex:POSITION;float2uv:TEXCOORD0;};structv2f{float2uv:TEXCOORD0;float4vertex:SV_POSITION;};sampler2D_MainTex;float4_MainTex_ST;fixed4_Color;v2fvert(appdatav){v2fo;o.vertex=UnityObjectToClipPos(v.vertex);o.uv=TRANSFORM_TEX(v.uv,_MainTex);returno;}fixed4frag(v2fi):SV_Target{fixed4col=tex2D(_MainTex,i.uv)*_Color;returncol;}ENDCG}}FallBack"Diffuse"}```###说明1.**透明度测试**:通过`clip`函数实现,当参数小于0时丢弃片元。它会产生硬边缘的透明效果。2.**透明度混合**:通过设置混合模式(Blend)关闭深度写入(ZWriteOff)来实现。它能够实现平滑的半透明效果,但渲染顺序很重要(通常从后往前渲染)。###注意事项-透明度测试性能较好,但边缘锯齿明显,可通过边缘抗锯齿技术改善。-透明度混合需要正确处理渲染顺序,否则可能出现错误的遮挡效果。-在混合模式下,通常需要关闭深度写入(ZWriteOff),但开启深度测试(ZTestOn,默认开启)以确保不透明物体能够遮挡半透明物体。§§相关问题§§1.如何在UnityShader中实现边缘抗锯齿的透明度测试?2.透明度混合的渲染顺序问题如何解决?3.UnityShader中除了透明度测试混合,还有哪些透明度处理技术?</think>### Unity Shader透明度设置教程 在Unity中设置Shader透明度主要通过两种技术实现:**透明度测试(Alpha Test)** **透明度混合(Alpha Blending)**。以下是详细步骤代码示例: --- #### 一、透明度测试(硬边缘透明) 原理:通过阈值完全丢弃低于阈值的像素,**无半透明效果**,性能较好[^1][^3]。 ```glsl Shader "Custom/AlphaTest" { Properties { _MainTex ("Texture", 2D) = "white" {} _Cutoff ("Alpha Cutoff", Range(0,1)) = 0.5 // 阈值控制 } SubShader { // 关键标签设置[^1][^3] Tags { "Queue"="AlphaTest" "RenderType"="TransparentCutout" "IgnoreProjector"="True" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag sampler2D _MainTex; float _Cutoff; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert (appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); // 透明度测试:丢弃低于阈值的像素 clip(col.a - _Cutoff); // 核心语句 return col; } ENDCG } } FallBack "Diffuse" } ``` **使用要点**: 1. 调整`_Cutoff`值(0-1)控制透明区域 2. 适用于树叶、栅栏等硬边缘透明物体 3. 标签必须包含`"Queue"="AlphaTest"`[^3] --- #### 二、透明度混合(半透明效果) 原理:通过混合公式实现**真正的半透明**,需处理渲染顺序[^2]。 ```glsl Shader "Custom/AlphaBlend" { Properties { _MainTex ("Texture", 2D) = "white" {} _AlphaScale ("Alpha Scale", Range(0,1)) = 1.0 } SubShader { // 关键标签设置[^2] Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" } Pass { // 关闭深度写入防止遮挡错误 ZWrite Off // 设置混合模式:源透明度 * 源色 + (1-源透明度) * 目标色 Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag sampler2D _MainTex; float _AlphaScale; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert (appdata_base v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.uv = v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); // 直接输出带透明度的颜色 return fixed4(col.rgb, col.a * _AlphaScale); } ENDCG } } FallBack "Transparent/Diffuse" } ``` **使用要点**: 1. `Blend`指令定义混合公式(常用`SrcAlpha OneMinusSrcAlpha`) 2. `ZWrite Off`避免深度写入问题 3. 标签必须包含`"Queue"="Transparent"`[^2] 4. 调整`_AlphaScale`控制整体透明度 --- ### 三、选择指南 | 特性 | 透明度测试 | 透明度混合 | |--------------|-------------------------------|-------------------------| | **效果** | 硬边缘透明(无渐变) | 真实半透明(有渐变) | | **性能** | 较高(无深度排序) | 较低(需排序) | | **适用场景** | 镂空贴图、硬边缘物体 | 玻璃、烟雾、液体 | | **深度写入** | 开启 | 关闭 | > 提示:半透明物体需按**从后向前**的顺序渲染,可在Unity中通过`Renderer.sortingOrder`控制[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值