1、介紹:如圖所示划乖,兩個膠囊體都是采用同樣的透明度混合方程進行混合的,并且顏色和透明度都一樣挤土。而左邊的對透明度進行了“特殊”的處理琴庵,就得到了和右邊不一樣的效果:膠囊體的邊沿輪廓增強。
配合采用貼圖的效果如圖所示:兩者都是采用了一樣的透明度貼圖以及透明度混合方法,左邊的是采用了輪廓增強的效果圖迷殿。
2儿礼、原理:首先,計算出模型表面的輪廓庆寺,這不廢話嗎蚊夫,其實還真不是廢話,因為并不是所有的模型我們都能預(yù)先知道它的輪廓懦尝,當(dāng)然經(jīng)過特殊處理的除外知纷。怎么樣去判斷模型的網(wǎng)格點是屬于輪廓邊緣上呢。
這里我們定義模型的網(wǎng)格點的法線方向為N如上圖所示的藍色線陵霉,攝像機的觀察方向為V琅轧。當(dāng)N和V方向正交的時候,也即V.N=0,我們就判斷這個點為輪廓點撩匕。實際上很少出現(xiàn)這種情況鹰晨,因此,我們將點積V.N接近于0的點都可以看做是靠近輪廓止毕。因此我們的透明度計算方程可以這么寫:a=min(1,a/|V.N|)模蜡。
3、實現(xiàn)效果的Shader代碼:
1>:不加貼圖的Shader代碼:
本帖隱藏的內(nèi)容
[C#]純文本查看復(fù)制代碼
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Unlit/Cg silhouette enhancement"
{
Properties{
_Color("Color", Color) = (1, 1, 1, 0.5)
// user-specified RGBA color including opacity
}
SubShader{
Tags{ "Queue" = "Transparent" }
// draw after all opaque geometry has been drawn
Pass{
ZWrite Off // don't occlude other objects
Blend SrcAlpha OneMinusSrcAlpha // standard alpha blending
//==float4 result = fragment_output.aaaa * fragment_output + (float4(1.0, 1.0, 1.0, 1.0) - fragment_output.aaaa) * pixel_color;
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float4 _Color; // define shader property for shaders
struct vertexInput {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct vertexOutput {
float4 pos : SV_POSITION;
float3 normal : TEXCOORD;
float3 viewDir : TEXCOORD1;
};
vertexOutput vert(vertexInput input)
{
vertexOutput output;
float4x4 modelMatrix = unity_ObjectToWorld;//模型矩陣
float4x4 modelMatrixInverse = unity_WorldToObject;//模型的逆矩陣
output.normal = normalize(
mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
output.viewDir = normalize(_WorldSpaceCameraPos
- mul(modelMatrix, input.vertex).xyz);
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return output;
}
float4 frag(vertexOutput input) : COLOR
{
//為什么在頂點著色器程序中已經(jīng)將這兩個向量歸一化了扁凛,在此為什么還要歸一化忍疾?
//1>首先,在頂點程序中歸一化是因為要在任何它們之間的方向上進行或多或少的插值
//2>在此處又進行一次插值是因為谨朝,上面的插值過程會將歸一化的值扭曲
float3 normalDirection = normalize(input.normal);
float3 viewDirection = normalize(input.viewDir);
float newOpacity = min(1.0, _Color.a
/ abs(dot(viewDirection, normalDirection)));
return float4(_Color.rgb, newOpacity);
}
ENDCG
}
}
}
2>:貼圖渲染的代碼:
將片段Shader的代碼替換成下面的代碼卤妒,
本帖隱藏的內(nèi)容
[C#]純文本查看復(fù)制代碼
float4 frag(vertexOutput input) : COLOR
{
//為什么在頂點著色器程序中已經(jīng)將這兩個向量歸一化了,在此為什么還要歸一化字币?
//1>首先则披,在頂點程序中歸一化是因為要在任何它們之間的方向上進行或多或少的插值
//2>在此處又進行一次插值是因為,上面的插值過程會將歸一化的值扭曲
float3 normalDirection = normalize(input.normal);
float3 viewDirection = normalize(input.viewDir);
float4 tex = tex2D(_MainTex, input.tex.xy);
float3 col = tex;
float newOpacity = min(1.0, tex.a / abs(dot(viewDirection, normalDirection)));
return float4(col, newOpacity);
}
ENDCG
}
4洗出、總結(jié):輪廓增強在很多效果的應(yīng)用都非常實用的士复,比如主角邊緣發(fā)光效果、渲染一些云母生物翩活,如下圖所示阱洪,總之是一個非常實用的小技巧。
原文參考資料來自
https://en.wikibooks.org/wiki/Cg_Programming/Unity/Silhouette_Enhancement