Unity制作二次元材質(zhì)角色
回到目錄
大家好,我是阿趙。
這里繼續(xù)來(lái)講二次元角色的材質(zhì)。上次講了光影的色階化問(wèn)題,這次繼續(xù)講光照模型效果的問(wèn)題。
之前我們說(shuō)過(guò),光照模型的最后效果是:
環(huán)境色+漫反射+高光+反射。
這里我們可以先忽略環(huán)境光,然后之前做了漫反射,用的是HalfLambert,剩下的就是高光和反射了
一、高光
繼續(xù)套用之前學(xué)過(guò)的高光光照模型,習(xí)慣上是使用BlinnPhong。
//獲取BlinnPhong高光
float GetBlinnPhongSpec(float3 worldPos, float3 worldNormal)
{
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfDir = normalize((viewDir + _WorldSpaceLightPos0.xyz));
float specDir = max(dot(normalize(worldNormal), halfDir), 0);
float specVal = pow(specDir, _shininess);
return specVal;
}
half4 frag (v2f i) : SV_Target
{
half4 col = tex2D(_BaseMap, i.uv);
half4 sssCol = tex2D(_SSSMap, i.uv);
//色階化
half halfLambert = GetHalfLambertDiffuse(i.worldPos, i.worldNormal);
half toonVal = smoothstep(_GradationMin, _GradationMax, halfLambert);
//高光
half specVal = GetBlinnPhongSpec(i.worldPos, i.worldNormal);
half3 finalRGB = col.rgb*toonVal + sssCol * (1 - toonVal) + _specColor * specVal;
half alpha = col.a;
return half4(finalRGB,alpha);
}
加上高光之后,模型就變成這樣了,高光有點(diǎn)強(qiáng)過(guò)頭了。先不管,把效果都加上,最后再調(diào)。
二、反射
熟悉我的朋友都知道了,加反射效果,阿趙一般是推薦Matcap的,特別是這種不需要真反射,只是要一點(diǎn)環(huán)境假反射的情況。
于是又找到Matcap的代碼,加上去。
float2 GetMatCapUV(float3 normalWorld)
{
float3 normalView = mul(UNITY_MATRIX_IT_MV, normalWorld);
return normalView.xy*0.5 + 0.5;
}
half4 frag (v2f i) : SV_Target
{
// sample the texture
half4 col = tex2D(_BaseMap, i.uv);
half4 sssCol = tex2D(_SSSMap, i.uv);
//色階化
half halfLambert = GetHalfLambertDiffuse(i.worldPos, i.worldNormal);
half toonVal = smoothstep(_GradationMin, _GradationMax, halfLambert);
//高光
half specVal = GetBlinnPhongSpec(i.worldPos, i.worldNormal);
//matcap
float2 MatCapUV = GetMatCapUV(i.worldNormal)*_MatCapUVScale;
float4 MatCapCol = tex2D(_MatCapTex, MatCapUV)*_MatCapIntensity;
MatCapCol = pow(MatCapCol, _MatCapPow);
half3 finalRGB = col.rgb*toonVal + sssCol * (1 - toonVal)+_specColor* specVal;
finalRGB = finalRGB * MatCapCol.rgb;
half alpha = col.a;
return half4(finalRGB,alpha);
}
這個(gè)效果,已經(jīng)加上了BlinnPhong高光、Matcap反射。但明顯效果是不對(duì)的,角色像一個(gè)少林寺十八銅人似的。
三、ILM貼圖
上面把高光和反射加上去之后,發(fā)現(xiàn)效果不對(duì)。那么需要怎樣去修正呢?
我們可以分析一下,效果不對(duì)的原因是什么:
1、某些部位的反射強(qiáng)度不對(duì),比如皮膚,不應(yīng)該反射這么強(qiáng)烈
2、高光的范圍不對(duì),有些部位的高光范圍應(yīng)該被控制在一個(gè)局部
3、反射的范圍不對(duì),反射不應(yīng)該所有地方都一樣的強(qiáng)度,應(yīng)該根據(jù)實(shí)際的材質(zhì)來(lái)顯示,比如皮膚是不會(huì)反射的,皮衣可能有一點(diǎn),吉他的金屬漆部分應(yīng)該有比較強(qiáng)的反射。
那么,我們應(yīng)該怎樣去控制這些強(qiáng)度和范圍呢?這里我們需要回顧一下,之前分析資源時(shí),得到的ILM貼圖的實(shí)際情況:
由于已經(jīng)知道ILM貼圖的A通道是內(nèi)描線,所以這里先忽略,只看RGB三個(gè)通道:
首先是R通道:
然后是G通道:
然后是B通道:
這里可以猜測(cè)一下,三個(gè)通道的作用了。
比較明顯的是R通道,他明顯是控制高光強(qiáng)弱的。
G通道的作用不是很明顯,只有臉部和身上某些部位是比較白,其他的顏色都一樣。這樣應(yīng)該是控制影子強(qiáng)度的,
B通道只有某些局部亮起來(lái),大部分都是黑的,可以理解成,是用來(lái)控制高光和反射的形狀范圍的。
于是我們可以把ILM貼圖對(duì)應(yīng)的通道的值,加在之前的高光和反射上面。
首先來(lái)看高光部分:
half4 frag (v2f i) : SV_Target
{
// sample the texture
half4 col = tex2D(_BaseMap, i.uv);
half4 sssCol = tex2D(_SSSMap, i.uv);
half4 ilmCol = tex2D(_ILMMap, i.uv);
//色階化
half halfLambert = GetHalfLambertDiffuse(i.worldPos, i.worldNormal);
half toonVal = smoothstep(_GradationMin, _GradationMax, halfLambert);
//高光
half specVal = GetBlinnPhongSpec(i.worldPos, i.worldNormal);
half3 finalRGB = col.rgb*toonVal + sssCol * (1 - toonVal)+_specColor* specVal*ilmCol.r+ _specColor * specVal*ilmCol.b*_SpecAdd;
half alpha = col.a;
return half4(finalRGB,alpha);
}
使用ILM貼圖的R通道控制高光強(qiáng)度,本來(lái)ILM貼圖的B通道是控制形狀的,我這里修改了一下用法,變成了在R通道控制完強(qiáng)度之后,使用B通道把某些區(qū)域的高光加強(qiáng)一下,比如胸部的光點(diǎn),衣服上的金屬邊的高光點(diǎn)等。于是就得到了這樣的效果:
再來(lái)看Matcap部分,直接用B通道控制范圍,為了看得更清楚一些,所以暫時(shí)把高光去掉:
half4 frag (v2f i) : SV_Target
{
// sample the texture
half4 col = tex2D(_BaseMap, i.uv);
half4 sssCol = tex2D(_SSSMap, i.uv);
half4 ilmCol = tex2D(_ILMMap, i.uv);
//色階化
half halfLambert = GetHalfLambertDiffuse(i.worldPos, i.worldNormal);
half toonVal = smoothstep(_GradationMin, _GradationMax, halfLambert);
float2 MatCapUV = GetMatCapUV(i.worldNormal)*_MatCapUVScale;
float4 MatCapCol = tex2D(_MatCapTex, MatCapUV)*_MatCapIntensity;
MatCapCol = pow(MatCapCol, _MatCapPow);
half3 finalRGB = col.rgb*toonVal + sssCol * (1 - toonVal);
finalRGB = finalRGB * (1-ilmCol.b) +MatCapCol.rgb*ilmCol.b;
half alpha = col.a;
return half4(finalRGB,alpha);
}
這時(shí)候可以看到,之前十八銅人一般的全身反射已經(jīng)沒(méi)有了,變成了只有指定的部位出現(xiàn)了反射效果。
最后,把ILM對(duì)高光和反射的影響一起加上,就得到了:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-513023.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-513023.html
四、完整Shader
Shader "azhao/ToonBodyLight"
{
Properties
{
_BaseMap ("BaseMap", 2D) = "white" {}
_SSSMap("SSSMap", 2D) = "white" {}
_ILMMap("ILMMap", 2D) = "white" {}
_specColor("specColor",Color) = (1,1,1,1)
_shininess("shininess", Range(1 , 100)) = 1
_SpecAdd("SpecAdd",float) = 1.0
_GradationMin("GradationMin",Range(0.0,1.0)) = 0.0
_GradationMax("GradationMax",Range(0.0,1.0)) = 1.0
_MatCapTex("MatCapTex", 2D) = "white" {}
_MatCapIntensity("MatCapIntensity",Range(0,2)) = 1
_MatCapPow("MatCapPow",Range(0,5)) = 1
_MatCapUVScale("MatCapUVScale",Range(0,1)) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#pragma multi_compile_fwdbase
#include "AutoLight.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float2 uv2 : TEXCOORD1;
float3 normal:NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uv2 : TEXCOORD1;
float3 worldPos :TEXCOORD2;
float3 worldNormal :TEXCOORD3;
};
sampler2D _BaseMap;
float4 _BaseMap_ST;
sampler2D _SSSMap;
sampler2D _ILMMap;
float4 _specColor;
float _shininess;
float _SpecAdd;
float _GradationMin;
float _GradationMax;
sampler2D _MatCapTex;
float _MatCapIntensity;
float _MatCapPow;
float _MatCapUVScale;
//獲取HalfLambert漫反射值
float GetHalfLambertDiffuse(float3 worldPos, float3 worldNormal)
{
float3 lightDir = UnityWorldSpaceLightDir(worldPos);
float NDotL = dot(worldNormal, lightDir);
float halfVal = NDotL * 0.5 + 0.5;
return halfVal;
}
//獲取BlinnPhong高光
float GetBlinnPhongSpec(float3 worldPos, float3 worldNormal)
{
float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
float3 halfDir = normalize((viewDir + _WorldSpaceLightPos0.xyz));
float specDir = max(dot(normalize(worldNormal), halfDir), 0);
float specVal = pow(specDir, _shininess);
return specVal;
}
float2 GetMatCapUV(float3 normalWorld)
{
float3 normalView = mul(UNITY_MATRIX_IT_MV, normalWorld);
return normalView.xy*0.5 + 0.5;
}
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
o.uv2 = TRANSFORM_TEX(v.uv2, _BaseMap);
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
half4 frag (v2f i) : SV_Target
{
// sample the texture
half4 col = tex2D(_BaseMap, i.uv);
half4 sssCol = tex2D(_SSSMap, i.uv);
half4 ilmCol = tex2D(_ILMMap, i.uv);
//色階化
half halfLambert = GetHalfLambertDiffuse(i.worldPos, i.worldNormal);
half toonVal = smoothstep(_GradationMin, _GradationMax, halfLambert);
//高光
half specVal = GetBlinnPhongSpec(i.worldPos, i.worldNormal);
//matcap
float2 MatCapUV = GetMatCapUV(i.worldNormal)*_MatCapUVScale;
float4 MatCapCol = tex2D(_MatCapTex, MatCapUV)*_MatCapIntensity;
MatCapCol = pow(MatCapCol, _MatCapPow);
half3 finalRGB = col.rgb*toonVal + sssCol * (1 - toonVal)+_specColor* specVal*ilmCol.r+ _specColor * specVal*ilmCol.b*_SpecAdd;
finalRGB = finalRGB * (1-ilmCol.b) +MatCapCol.rgb*ilmCol.b;
half alpha = col.a;
return half4(finalRGB,alpha);
}
ENDCG
}
}
}
到了這里,關(guān)于Unity制作二次元卡通渲染角色材質(zhì)——3、高光反射與ILM貼圖的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!