效果图
素描
素描效果是非真实渲染章节实现的一个效果,还是蛮有意思的。
实现方法
主要是根据物体的光照系数,来决定哪些浅,哪些深,哪些白,然后再使用这些素描纹理,进行采样填充。
轮廓线的实现,主要是顶点上的偏移,要注意的是它们是在视图空间下 完成计算的,它只计算背面,因此需要 剔除前面。
主要实现
在顶点作色器中计算光照系数,根据光照结果来决定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,分别代表 模型的各个部分。
由浅到深。
最后再计算光照衰减, 就完成了。