整容模板高允真
0.本文示例代碼地址
1. 極簡(jiǎn)描邊
1.1 思路
使用兩個(gè) Pass 來渲染秩命,兩個(gè) Pass 的作用分別是
- 把模型放大一定倍數(shù)挠轴,渲染成純色
- 正常渲染模型
這樣,因?yàn)榈谝粋€(gè)純色 Pass 把模型放大了箱蟆,所以第二個(gè)正常渲染 Pass 之外能看到一圈純色的描邊默穴,問題在于第一個(gè) Pass 的時(shí)候如何把模型放大呢怔檩?答案是:
把模型的每個(gè)頂點(diǎn)往該頂點(diǎn)的法線方向偏移一定位置
1.2 代碼
Shader "Custom_Shader/Outline"
{
Properties
{
_OutlineColor ("Color", Color) = (0, 0, 0, 0)
_OutlineWidth ("OutlineWidth", Range(0, 1)) = 0.1
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
};
float4 _OutlineColor;
float _OutlineWidth;
v2f vert (appdata v)
{
v2f o;
// 在模型空間法線外擴(kuò)
v.vertex.xyz = v.vertex.xyz + v.normal * _OutlineWidth;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
return _OutlineColor;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float4 _OutlineColor;
float _OutlineWidth;
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
關(guān)鍵代碼分析:
v2f vert (appdata v)
{
v2f o;
// 在模型空間法線外擴(kuò)
v.vertex.xyz = v.vertex.xyz += normalize(v.normal) * _OutlineWidth;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
在第一個(gè) Pass 的頂點(diǎn)著色器中來“放大”模型,這里是在模型空間進(jìn)行放大蓄诽,你愿意的話完全可以變換到世界空間進(jìn)行法線外擴(kuò)薛训。最終渲染效果都是一樣的,但這里需要注意的是如果將法線從模型空間變換到世界空間仑氛,需要使用變換矩陣 M 的逆轉(zhuǎn)置矩陣來進(jìn)行變化乙埃。
頂點(diǎn)從模型空間變換到世界空間:
float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
法線從模型空間變換到世界空間:
o.normal = mul(v.normal, (float3x3)unity_WorldToObject);
還注意到第一個(gè) Pass 有關(guān)閉深度寫入:
Pass
{
ZWrite Off
為什么第一個(gè) Pass 要關(guān)閉 ZWrite?
因?yàn)檎麄€(gè)模型放大了锯岖,面向攝像機(jī)的部分會(huì)比原始模型更接近攝像機(jī)介袜,寫入深度會(huì)導(dǎo)致第二個(gè) Pass 渲染時(shí)面向攝像機(jī)部分因?yàn)樯疃葴y(cè)試沒通過而沒有渲染出來,得不到正確的結(jié)果出吹。
1.3 效果
描邊效果