标签:des style blog http io color ar os 使用
好久没写博客了,一定是因为课程作业比较多,一定不是因为我懒,恩恩。
三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平缓的模型有效。这是因为我们是依赖法线和视角的点乘结果来进行描边判断的,因此,对于那些平整的表面,它们的法线通常是一个常量或者会发生突变(例如立方体的每个面),这样就会导致最后的效果并非如我们所愿。如下图所示:
因此,我们有一个更好的方法来实现描边效果,也就是通过两个pass进行渲染——首先渲染对象的背面,用黑色略微向外扩展一点,就是我们的描边效果;然后正常渲染正面即可。而我们应该知道,surface shader是不可以使用pass的。
在这篇里,我们就会学习如何使用Vertex & Fragment Shader来实现上述的过程。很显然,这样的一个过程包含了两个步骤——描边和正常的渲染。
最后的效果如下:
在上一篇里,我们使用了边缘高光来实现描边。而这篇里,我们将使用一个单独的pass来得到一个更好的效果。这里说的“更好”指的是以下几个方面:
Cull Front Lighting Off
float4 frag(v2f i) : COLOR { return float4(0, 0, 0, 1); }
struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; };
float _Outline; v2f vert (a2v v) { v2f o; o.pos = mul( UNITY_MATRIX_MVP, v.vertex + (float4(v.normal,0) * _Outline)); return o; }
Cull Front Lighting Off ZWrite On
v2f vert (a2v v) { v2f o; float4 pos = mul( UNITY_MATRIX_MV, v.vertex); float3 normal = mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal); normal.z = -0.4; pos = pos + float4(normalize(normal),0) * _Outline; o.pos = mul(UNITY_MATRIX_P, pos); return o; }
Shader "MyToon/Toon-Fragment" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Ramp ("Ramp Texture", 2D) = "white" {} _Tooniness ("Tooniness", Range(0.1,20)) = 4 _Outline ("Outline", Range(0,1)) = 0.1 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Pass { Tags { "LightMode"="ForwardBase" } Cull Front Lighting Off ZWrite On CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" float _Outline; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; }; v2f vert (a2v v) { v2f o; float4 pos = mul( UNITY_MATRIX_MV, v.vertex); float3 normal = mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal); normal.z = -0.5; pos = pos + float4(normalize(normal),0) * _Outline; o.pos = mul(UNITY_MATRIX_P, pos); return o; } float4 frag(v2f i) : COLOR { return float4(0, 0, 0, 1); } ENDCG } Pass { Tags { "LightMode"="ForwardBase" } Cull Back Lighting On CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityShaderVariables.cginc" sampler2D _MainTex; sampler2D _Ramp; float4 _MainTex_ST; float _Tooniness; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 tangent : TANGENT; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float3 normal : TEXCOORD1; LIGHTING_COORDS(2,3) }; v2f vert (a2v v) { v2f o; //Transform the vertex to projection space o.pos = mul( UNITY_MATRIX_MVP, v.vertex); o.normal = mul((float3x3)_Object2World, SCALED_NORMAL); //Get the UV coordinates o.uv = TRANSFORM_TEX (v.texcoord, _MainTex); // pass lighting information to pixel shader TRANSFER_VERTEX_TO_FRAGMENT(o); return o; } float4 frag(v2f i) : COLOR { //Get the color of the pixel from the texture float4 c = tex2D (_MainTex, i.uv); //Merge the colours c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness); //Based on the ambient light float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz; //Work out this distance of the light float atten = LIGHT_ATTENUATION(i); //Angle to the light float diff = dot (normalize(i.normal), normalize(_WorldSpaceLightPos0.xyz)); diff = diff * 0.5 + 0.5; //Perform our toon light mapping diff = tex2D(_Ramp, float2(diff, 0.5)); //Update the colour lightColor += _LightColor0.rgb * (diff * atten); //Product the final color c.rgb = lightColor * c.rgb * 2; return c; } ENDCG } Pass { Tags { "LightMode"="ForwardAdd" } Cull Back Lighting On Blend One One CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdadd #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityShaderVariables.cginc" sampler2D _MainTex; sampler2D _Ramp; float4 _MainTex_ST; float _Tooniness; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 tangent : TANGENT; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float3 normal : TEXCOORD1; half3 lightDir : TEXCOORD2; LIGHTING_COORDS(3,4) }; v2f vert (a2v v) { v2f o; //Transform the vertex to projection space o.pos = mul( UNITY_MATRIX_MVP, v.vertex); o.normal = mul((float3x3)_Object2World, SCALED_NORMAL); o.lightDir = WorldSpaceLightDir( v.vertex ); //Get the UV coordinates o.uv = TRANSFORM_TEX (v.texcoord, _MainTex); // pass lighting information to pixel shader TRANSFER_VERTEX_TO_FRAGMENT(o); return o; } float4 frag(v2f i) : COLOR { //Get the color of the pixel from the texture float4 c = tex2D (_MainTex, i.uv); //Merge the colours c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness); //Based on the ambient light float3 lightColor = float3(0); //Work out this distance of the light float atten = LIGHT_ATTENUATION(i); //Angle to the light float diff = dot (normalize(i.normal), normalize(i.lightDir)); diff = diff * 0.5 + 0.5; //Perform our toon light mapping diff = tex2D(_Ramp, float2(diff, 0.5)); //Update the colour lightColor += _LightColor0.rgb * (diff * atten); //Product the final color c.rgb = lightColor * c.rgb * 2; return c; } ENDCG } } FallBack "Diffuse" }
Shader "MyToon/Toon-Fragment_Normal" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _Bump ("Bump", 2D) = "bump" {} _Ramp ("Ramp Texture", 2D) = "white" {} _Tooniness ("Tooniness", Range(0.1,20)) = 4 _Outline ("Outline", Range(0,1)) = 0.1 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Pass { Tags { "LightMode"="ForwardBase" } Cull Front Lighting Off ZWrite On CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" float _Outline; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; }; struct v2f { float4 pos : POSITION; }; v2f vert (a2v v) { v2f o; float4 pos = mul( UNITY_MATRIX_MV, v.vertex); float3 normal = mul( (float3x3)UNITY_MATRIX_IT_MV, v.normal); normal.z = -0.5; pos = pos + float4(normalize(normal),0) * _Outline; o.pos = mul(UNITY_MATRIX_P, pos); return o; } float4 frag(v2f i) : COLOR { return float4(0, 0, 0, 1); } ENDCG } Pass { Tags { "LightMode"="ForwardBase" } Cull Back Lighting On CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdbase #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityShaderVariables.cginc" sampler2D _MainTex; sampler2D _Bump; sampler2D _Ramp; float4 _MainTex_ST; float4 _Bump_ST; float _Tooniness; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 tangent : TANGENT; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; float3 lightDirection : TEXCOORD2; LIGHTING_COORDS(3,4) }; v2f vert (a2v v) { v2f o; //Create a rotation matrix for tangent space TANGENT_SPACE_ROTATION; //Store the light‘s direction in tangent space o.lightDirection = mul(rotation, ObjSpaceLightDir(v.vertex)); //Transform the vertex to projection space o.pos = mul( UNITY_MATRIX_MVP, v.vertex); //Get the UV coordinates o.uv = TRANSFORM_TEX (v.texcoord, _MainTex); o.uv2 = TRANSFORM_TEX (v.texcoord, _Bump); // pass lighting information to pixel shader TRANSFER_VERTEX_TO_FRAGMENT(o); return o; } float4 frag(v2f i) : COLOR { //Get the color of the pixel from the texture float4 c = tex2D (_MainTex, i.uv); //Merge the colours c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness); //Get the normal from the bump map float3 n = UnpackNormal(tex2D (_Bump, i.uv2)); //Based on the ambient light float3 lightColor = UNITY_LIGHTMODEL_AMBIENT.xyz; //Work out this distance of the light float atten = LIGHT_ATTENUATION(i); //Angle to the light float diff = saturate (dot (n, normalize(i.lightDirection))); //Perform our toon light mapping diff = tex2D(_Ramp, float2(diff, 0.5)); //Update the colour lightColor += _LightColor0.rgb * (diff * atten); //Product the final color c.rgb = lightColor * c.rgb * 2; return c; } ENDCG } Pass { Tags { "LightMode"="ForwardAdd" } Cull Back Lighting On Blend One One CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fwdadd #include "UnityCG.cginc" #include "Lighting.cginc" #include "AutoLight.cginc" #include "UnityShaderVariables.cginc" sampler2D _MainTex; sampler2D _Bump; sampler2D _Ramp; float4 _MainTex_ST; float4 _Bump_ST; float _Tooniness; struct a2v { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 tangent : TANGENT; }; struct v2f { float4 pos : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; float3 lightDirection : TEXCOORD2; LIGHTING_COORDS(3,4) }; v2f vert (a2v v) { v2f o; //Create a rotation matrix for tangent space TANGENT_SPACE_ROTATION; //Store the light‘s direction in tangent space o.lightDirection = mul(rotation, ObjSpaceLightDir(v.vertex)); //Transform the vertex to projection space o.pos = mul( UNITY_MATRIX_MVP, v.vertex); //Get the UV coordinates o.uv = TRANSFORM_TEX (v.texcoord, _MainTex); o.uv2 = TRANSFORM_TEX (v.texcoord, _Bump); // pass lighting information to pixel shader TRANSFER_VERTEX_TO_FRAGMENT(o); return o; } float4 frag(v2f i) : COLOR { //Get the color of the pixel from the texture float4 c = tex2D (_MainTex, i.uv); //Merge the colours c.rgb = (floor(c.rgb*_Tooniness)/_Tooniness); //Get the normal from the bump map float3 n = UnpackNormal(tex2D (_Bump, i.uv2)); //Based on the ambient light float3 lightColor = float3(0); //Work out this distance of the light float atten = LIGHT_ATTENUATION(i); //Angle to the light float diff = saturate (dot (n, normalize(i.lightDirection))); //Perform our toon light mapping diff = tex2D(_Ramp, float2(diff, 0.5)); //Update the colour lightColor += _LightColor0.rgb * (diff * atten); //Product the final color c.rgb = lightColor * c.rgb * 2; return c; } ENDCG } } FallBack "Diffuse" }
读者有需要的可以自己添加上视角方向的采样,也就是说在v2f里添加一个新的变量viewDir,然后逐顶点计算后传递给frag函数。如果我后面有时间的话可能会回头添加上。当然,大家还是靠自己比较好。
【Unity Shader实战】卡通风格的Shader(二)
标签:des style blog http io color ar os 使用
原文地址:http://blog.csdn.net/candycat1992/article/details/41120019