• Unity 通用透明物体漫反射Shader(双面渲染&多光源&光照衰减&法线贴图&凹凸透明度控制)


    Shader "MyUnlit/AlphaBlendDiffuse"
    {
        Properties
        {
    		_Color("Color Tint(贴图染色)",Color)=(1,1,1,1)
            _MainTex ("Texture(主贴图)", 2D) = "white" {}
    	    //bump为unity内置的法线纹理,当未配置任何法线纹理时,bump对应模型自带的法线信息
    	    _NormalMap("Normal Map(法线贴图)",2D)="bump"{}
    		_BumpScale("Bump Scale(凹凸程度)",float) = 1.0
    		_Cutoff("Alpha(整体透明度)",range(0,1)) = 0.5
    	}
    	SubShader
    	{
    		//透明度混合需要定义的标签
    		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
    
    		//1.Base Pass背面(顺序,透明物体先渲染背面再渲染正面)
    		Pass
    		{
    			//提示此Pass为前向渲染中的Base Pass,计算环境光,自发光,平行光中的阴影,不计算其他叠加光照效果
    			Tags{ "LightMode" = "ForwardBase" }
    			//透明度混合需要关闭深度写入
    			ZWrite Off
    			//开启混合操作并设置混合类型,此处类型为透明度混合
    			Blend SrcAlpha OneMinusSrcAlpha
    			//透明物体要考虑双面渲染,第一个Pass只渲染背面,剔除正面
    			Cull Front
    
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag
    			//Base Pass指令,用于得到对应的光照变量
    			#pragma multi_compile_fwdbase
    
    			#include "UnityCG.cginc"
    			//包含接收阴影的宏
    			#include "AutoLight.cginc"
                #include "Lighting.cginc"
    
    			fixed4 _Color;
    		    sampler2D _MainTex;
    			//用于控制对应纹理的缩放和偏移,格式固定为xx_ST
    			float4 _MainTex_ST;
    			sampler2D _NormalMap;
    			float4 _NormalMap_ST;
    			float _BumpScale;
    			fixed _Cutoff;//[0,1]范围内用fixed
    
                struct appdata
                {
                    float4 vertex : POSITION;
    				float3 normal:NORMAL;
    				float4 tangent:TANGENT;//与法线不同,w需要用于控制朝向
                    float2 uv : TEXCOORD0;
                };
    
                struct v2f
                {
    				//节约空间,xy分量存主贴图uv;zw存法线贴图的
                    float4 uv : TEXCOORD0;
                    float4 pos : SV_POSITION;//变量名为pos,有关阴影计算的宏中使用了此变量
    				//寄存器中没法存矩阵,所以分别存矩阵的每一行
    				float4 TtoW0 : TEXCOORD1;
    				float4 TtoW1 : TEXCOORD2;
    				float4 TtoW2 : TEXCOORD3;
    				SHADOW_COORDS(4)//此阴影纹理坐标存储在TEXCOORD4中
                };
    
    			//此处采用在世界空间中计算法线
                v2f vert (appdata v)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(v.vertex);
    				//用两个分量分别存储贴图的缩放和偏移
                    o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
    				o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap);
    
    				float3 worldPos= mul(unity_ObjectToWorld, v.vertex).xyz;
    				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    				//叉积计算第三个标准正交基轴向,w指示朝向的正负
    				fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    				//节约空间,顺便将世界空间中的顶点位置存在w分量中
    				o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
    				o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
    				o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
    				//计算阴影纹理坐标
    				TRANSFER_SHADOW(o);
    
    				return o;
                }
    
                fixed4 frag (v2f i) : SV_Target
                {
    				//还原世界坐标
    				float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
    				//还原出矩阵,用于将纹理从顶点空间(切线空间)变为世界空间,统一计算
    				float3x3 TtoW= float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz);
    				//得到世界空间中的光源方向和视线方向
    				fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
    				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
    				//从zw分量中采样出法线并进行凹凸程度的缩放,但此时法线依然处于顶点空间(切线空间)
    				fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale);
    				//通过之前构造的变换矩阵将法线从顶点空间变换到世界空间
    				fixed3 worldNormal = mul(TtoW, tanNormal);
    				//采样主纹理并染色,得到反射率
                    fixed4 col = tex2D(_MainTex, i.uv);
    				fixed3 albedo = col.rgb*_Color.rgb;
    				//计算环境光
    				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    				//计算漫反射
    				fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal));
    				//计算光照和阴影衰减值,结果为第一个参数
    				UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
    
    				//返回计算结果
                    return fixed4(ambient + diffuse * atten, col.a * _Cutoff);
                }
                ENDCG
            }
    		//2.Base Pass正面
    		Pass
    		{
    			Tags{ "LightMode" = "ForwardBase" }
    
    			ZWrite Off
    			Blend SrcAlpha OneMinusSrcAlpha
    			//透明物体要考虑双面渲染,此Pass只渲染正面,剔除背面
    			Cull Back
    
    			CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_fwdbase
    
                #include "UnityCG.cginc"
                #include "AutoLight.cginc"
                #include "Lighting.cginc"
    
    			fixed4 _Color;
    		    sampler2D _MainTex;
    		    float4 _MainTex_ST;
    		    sampler2D _NormalMap;
    		    float4 _NormalMap_ST;
    		    float _BumpScale;
    		    fixed _Cutoff;
    
    		struct appdata
    		{
    			float4 vertex : POSITION;
    			float3 normal:NORMAL;
    			float4 tangent:TANGENT;
    			float2 uv : TEXCOORD0;
    		};
    
    		struct v2f
    		{
    			float4 uv : TEXCOORD0;
    			float4 pos : SV_POSITION;
    
    			float4 TtoW0 : TEXCOORD1;
    			float4 TtoW1 : TEXCOORD2;
    			float4 TtoW2 : TEXCOORD3;
    			SHADOW_COORDS(4)
    		};
    
    		v2f vert(appdata v)
    		{
    			v2f o;
    			o.pos = UnityObjectToClipPos(v.vertex);
    			o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
    			o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap);
    
    			float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    			fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    			fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    
    			fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    
    			o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
    			o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
    			o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
    
    			TRANSFER_SHADOW(o);
    
    			return o;
    		}
    
    		fixed4 frag(v2f i) : SV_Target
    		{
    
    			float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
    
    			float3x3 TtoW = float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz);
    
    			fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
    			fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
    
    			fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale);
    
    			fixed3 worldNormal = mul(TtoW, tanNormal);
    
    			fixed4 col = tex2D(_MainTex, i.uv);
    			fixed3 albedo = col.rgb*_Color.rgb;
    
    			fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    
    			fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal));
    
    			UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
    
    			return fixed4(ambient + diffuse * atten, col.a * _Cutoff);
    		}
    			ENDCG
    		}
    		//3.Add Pass正常渲染
    		Pass
    		{
    			//提示此Pass为前向渲染中的Add Pass,计算其他叠加光照效果,每个光源计算一次
    			Tags{ "LightMode" = "ForwardAdd" }
    
    			ZWrite Off
    			Blend SrcAlpha One
    			Cull Back
    
    			CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
    			//Add Pass指令,用于得到对应的光照变量
                //#pragma multi_compile_fwdadd
    			//阴影情况下使用:
    			#pragma multi_compile_fwdadd_fullshadows
    
                #include "UnityCG.cginc"
                #include "AutoLight.cginc"
                #include "Lighting.cginc"
    
    			fixed4 _Color;
    		    sampler2D _MainTex;
    		    float4 _MainTex_ST;
    		    sampler2D _NormalMap;
    		    float4 _NormalMap_ST;
    		    float _BumpScale;
    		    fixed _Cutoff;
    
    		struct appdata
    		{
    			float4 vertex : POSITION;
    			float3 normal:NORMAL;
    			float4 tangent:TANGENT;
    			float2 uv : TEXCOORD0;
    		};
    
    		struct v2f
    		{			
    			float4 uv : TEXCOORD0;
    			float4 pos : SV_POSITION;
    
    			float4 TtoW0 : TEXCOORD1;
    			float4 TtoW1 : TEXCOORD2;
    			float4 TtoW2 : TEXCOORD3;
    			SHADOW_COORDS(4)
    		};
    
    		v2f vert(appdata v)
    		{
    			v2f o;
    			o.pos = UnityObjectToClipPos(v.vertex);
    			o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
    			o.uv.zw = TRANSFORM_TEX(v.uv, _NormalMap);
    
    			float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    			fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    			fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    
    			fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    
    			o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
    			o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
    			o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
    
    			TRANSFER_SHADOW(o);
    
    			return o;
    		}
    
    		fixed4 frag(v2f i) : SV_Target
    		{
    
    			float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
    
    			float3x3 TtoW = float3x3(i.TtoW0.xyz, i.TtoW1.xyz, i.TtoW2.xyz);
    
    			fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
    			fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
    
    			fixed3 tanNormal = UnpackNormalWithScale(tex2D(_NormalMap, i.uv.zw), _BumpScale);
    
    			fixed3 worldNormal = mul(TtoW, tanNormal);
    
    			fixed4 col = tex2D(_MainTex, i.uv);
    			fixed3 albedo = col.rgb*_Color.rgb;
    
    			fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
    
    			fixed3 diffuse = _LightColor0.rgb*albedo*saturate(dot(lightDir, worldNormal));
    
    			UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
    
    			return fixed4(ambient + diffuse * atten, col.a * _Cutoff);
    		}
    			ENDCG
    		}
        }
    	//无阴影
    	//FallBack "Transparent/VertexLit"
    	//强制产生阴影
    	FallBack "VertexLit"
    }
    

      

    对于至今为止Shader学习内容的一个总结,算是一个比较综合通用的shader了,因为是漫反射所以暂时没有计算高光部分,之后再出一个带高光版本的。

    备注都有比较详细的说明,基本思路是利用多个Pass分别进行正反面的渲染,再结合前向渲染的分光照渲染来实现。

    最后摆出效果图w~

    不带投影的结果带投影的结果

  • 相关阅读:
    【原创】express3.4.8源码解析之Express结构图
    【原创】backbone1.1.0源码解析之View
    【原创】javascript模板引擎的简单实现
    【原创】backbone1.1.0源码解析之Collection
    【原创】when.js2.7.1源码解析
    【原创】backbone1.1.0源码解析之Model
    【原创】backbone1.1.0源码解析之Events
    企业架构研究总结(35)——TOGAF架构内容框架之构建块(Building Blocks)
    企业架构研究总结(34)——TOGAF架构内容框架之架构制品(下)
    企业架构研究总结(33)——TOGAF架构内容框架之架构制品(上)
  • 原文地址:https://www.cnblogs.com/koshio0219/p/11098966.html
Copyright © 2020-2023  润新知