//--------------------------- 【描边】 - 法线扩张--------------------- //create by 长生但酒狂 Shader "lcl/shader3D/outLine3D_swell" { //---------------------------【属性】--------------------------- Properties { // 主纹理 _MainTex("Texture", 2D) = "white" {} // 主颜色 _Color("Color",Color) = (1,1,1,1) // 描边强度 _power("power",Range(0,0.2)) = 0.05 // 描边颜色 _lineColor("lineColor",Color) = (1,1,1,1) } // ------------------------【CG代码】--------------------------- CGINCLUDE #include "UnityCG.cginc" #include "Lighting.cginc" //顶点着色器输入结构体 struct appdata { float4 vertex : POSITION;//顶点坐标 float2 uv : TEXCOORD0;//纹理坐标 float3 normal:NORMAL;//法线 }; //顶点着色器输出结构体 struct v2f { float4 vertex : SV_POSITION;//像素坐标 float2 uv : TEXCOORD0;//纹理坐标 float3 worldNormalDir:COLOR0;//世界空间里的法线方向 float3 worldPos:COLOR1;//世界空间里的坐标 }; // ------------------------【变量声明】--------------------------- //纹理 sampler2D _MainTex; //内置的变量,纹理中的单像素尺寸 float4 _MainTex_TexelSize; //主颜色 float4 _Color; //描边强度 float _power; //描边颜色 float4 _lineColor; // ------------------------【背面-顶点着色器】--------------------------- v2f vert_back(appdata v) { v2f o; //法线方向 v.normal = normalize(v.normal); //顶点沿着法线方向扩张 v.vertex.xyz += v.normal * _power; //由模型空间坐标系转换到裁剪空间 o.vertex = UnityObjectToClipPos(v.vertex); //输出结果 return o; } // ------------------------【背面-片元着色器】--------------------------- fixed4 frag_back(v2f i) : SV_Target { //直接输出颜色 return _lineColor; } // ------------------------【正面-顶点着色器】--------------------------- v2f vert_front(appdata v) { //正常渲染 v2f o; o.uv = v.uv; //法线从模型空间坐标系转换到世界坐标系 o.worldNormalDir = mul(v.normal, (float3x3) unity_WorldToObject); //顶点从模型空间坐标系转换到世界坐标系 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; //归一化 v.normal = normalize(v.normal); //由模型空间坐标系转换到裁剪空间 o.vertex = UnityObjectToClipPos(v.vertex); return o; } // ------------------------【正面-片元着色器】--------------------------- fixed4 frag_front(v2f i) : SV_Target { //正常渲染 //纹理颜色值 fixed4 col = tex2D(_MainTex, i.uv); //环境光 fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * _Color.xyz; //视角方向 float3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)); //法线方向 float3 normaleDir = normalize(i.worldNormalDir); //光照方向归一化 fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); //半兰伯特模型 fixed3 lambert = 0.5 * dot(normaleDir, worldLightDir) + 0.5; //漫反射 fixed3 diffuse = lambert * _Color.xyz * _LightColor0.xyz + ambient; //最终结果 fixed3 result = diffuse * col.xyz; return float4(result,1); } ENDCG // ------------------------【子着色器】--------------------------- SubShader { //透明度混合模式 Blend SrcAlpha OneMinusSrcAlpha //渲染队列 Tags{ "Queue" = "Transparent" } // ------------------------【背面通道】--------------------------- Pass { //剔除正面 Cull Front //防止背面模型穿透正面模型 //关闭深度写入,为了让正面的pass完全覆盖背面,同时要把渲染队列改成Transparent,此时物体渲染顺序是从后到前的 ZWrite Off CGPROGRAM #pragma vertex vert_back #pragma fragment frag_back ENDCG } // ------------------------【正面通道】--------------------------- Pass { //剔除背面 Cull Back CGPROGRAM #pragma vertex vert_front #pragma fragment frag_front ENDCG } } }