标签: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