效果圖
素描
素描效果是非真實渲染章節實現的一個效果,還是蠻有意思的。
實現方法
主要是根據物體的光照係數,來決定哪些淺,哪些深,哪些白,然後再使用這些素描紋理,進行採樣填充。
輪廓線的實現,主要是頂點上的偏移,要注意的是它們是在視圖空間下 完成計算的,它只計算背面,因此需要 剔除前面。
主要實現
在頂點作色器中計算光照係數,根據光照結果來決定6張爲你的混合權重,並傳遞給片元作色器,然後在片元作色器根據這些權重來混合6張紋理的採樣結果。
定義所需的屬性
Properties
{
_Color("Color",Color)=(1,1,1,1)
_TintFactor("TintFactor",float)=8
_OutLine("OutLine",Range(0,1))=1
_OutLineColor("OutLineColor",Color)=(1,1,1,1)
_Hatch0("Hatch 0",2D)="white" {}
_Hatch1("Hatch 1",2D)="white" {}
_Hatch2("Hatch 2",2D)="white" {}
_Hatch3("Hatch 3",2D)="white" {}
_Hatch4("Hatch 4",2D)="white" {}
_Hatch5("Hatch 5",2D)="white" {}
}
計算輪廓線
pass
{
Cull Front
Tags{"RenderType"="Opaque" "Queue"="Geometry"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _OutLine;
float4 _OutLineColor;
struct a2v
{
float4 vertex:POSITION;
float3 normal:normal;
};
struct v2f
{
float4 pos:SV_POSITION;
};
v2f vert(a2v v)
{
v2f o;
float3 pos=UnityObjectToViewPos(v.vertex);
float3 normal=mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
normal.z=-0.5; //爲了防止內凹
pos=pos+normalize(normal)*_OutLine;
o.pos=mul(UNITY_MATRIX_P,float4(pos,1));
return o;
}
float4 frag(v2f v):SV_TARGET
{
return fixed4(_OutLineColor.rgb,1);
}
ENDCG
}
需要剔除前面,在片元着色器中,只計算描邊的顏色。
在頂點作色器中
o.pos=mul(UNITY_MATRIX_P,float4(pos,1)); 使用的是當前投影矩陣,把視圖空間下計算好偏移的pos轉換到當前投影空間下。
如果不設置法線 z可能會出現 這種情況
視圖空間下,法線*offset 就是向外擴展offet倍,歸一化後,只得到了垂直物體表面,向外的方向。
另一個通道 處理物體的前面,剔除背面
pass
{
Cull Back
Tags{"RenderType"="Opaque" "Queue"="Geometry"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct a2v{
float4 vertex:POSITION;
float3 normal:NORMAL;
float4 texcoord:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0;
float3 hatchWeight0:TEXCOORD1;
float3 hatchWeight1:TEXCOORD2;
float3 worldPos:TEXCOORD3;
SHADOW_COORDS(4)
};
float4 _Color;
sampler2D _Hatch0;
sampler2D _Hatch1;
sampler2D _Hatch2;
sampler2D _Hatch3;
sampler2D _Hatch4;
sampler2D _Hatch5;
float _OutLine;
float _TintFactor;
v2f vert(a2v v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.texcoord.xy*_TintFactor;
o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
float3 worldNormal=normalize( UnityObjectToWorldNormal(v.normal));
//float3 wordViewDir=normalize(UnityWorldSpaceViewDir(o.worldPos.xyz));
float3 worldLightDir=-normalize(UnityWorldSpaceLightDir(o.worldPos));
//float3 halfDir=normalize(wordViewDir+worldLightDir);
o.hatchWeight0=float3(0,0,0);
o.hatchWeight1=float3(0,0,0);
float diff=dot(worldNormal,worldLightDir);
diff=clamp(diff,0.005,1);//防止背部全黑
float hatchFactor=diff*7;
if(hatchFactor>6)
{
}
else if(hatchFactor>5)
{
o.hatchWeight0.x=hatchFactor-5;
}else if(hatchFactor>4)
{
o.hatchWeight0.x=hatchFactor-4;
o.hatchWeight0.y=1-o.hatchWeight0.x;
}
else if(hatchFactor>3)
{
o.hatchWeight0.y=hatchFactor-3;
o.hatchWeight0.z=1-o.hatchWeight0.y;
}
else if(hatchFactor>2)
{
o.hatchWeight0.z=hatchFactor-2;
o.hatchWeight1.x=1-o.hatchWeight0.z;
}
else if(hatchFactor>1)
{
o.hatchWeight1.x=hatchFactor-1;
o.hatchWeight1.y=1-o.hatchWeight1.x;
}
else
{
o.hatchWeight1.y=hatchFactor;
o.hatchWeight1.z=1-o.hatchWeight1.y;
}
TRANSFER_SHADOW(o);
return o;
}
fixed4 frag(v2f i):SV_TARGET
{
fixed4 hatchTex0=tex2D(_Hatch0,i.uv)*i.hatchWeight0.x;
fixed4 hatchTex1=tex2D(_Hatch1,i.uv)*i.hatchWeight0.y;
fixed4 hatchTex2=tex2D(_Hatch2,i.uv)*i.hatchWeight0.z;
fixed4 hatchTex3=tex2D(_Hatch3,i.uv)*i.hatchWeight1.x;
fixed4 hatchTex4=tex2D(_Hatch4,i.uv)*i.hatchWeight1.y;
fixed4 hatchTex5=tex2D(_Hatch5,i.uv)*i.hatchWeight1.z;
fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);
fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;
UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
return fixed4(_Color.rgb*atten*hatchColor.rgb,1);
}
o.uv=v.texcoord.xy*_TintFactor;
這裏是計算紋理的密集度
在vert中 計算diffuse= dot(n,l) n爲法線方向,l爲光照方向,
然後擴大7倍,分別對應6張紋理 和全白區域;
分別計算 x0 ,x0y0,y0z0,z0x1,x1y1,z1;的係數
在frag中
fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);
這裏白色 計算就是 全白色減去上面所有diffuse不爲0的情況,
用1 減去,是因爲 diffuse 最高爲1,代表全亮,這裏計算結束,所有剩下的就是亮的部分了。
fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;
最後最終結果就是它們所有 採樣的顏色相加;
0,1,2,3,4,5,分別代表 模型的各個部分。
由淺到深。
最後再計算光照衰減, 就完成了。