边缘检测有很多方法,这里讲的是基于法线的边缘检测。
需要的知识有RTT(Render to target),嗯,没错就这么简单,你只要会RTT,两分钟就搞定这个算法。
这个算法的核心思想就是利用物体的边缘法线会发生变化,而法线变化越大,两个法线点积的值就越小。
那么如何获取法线呢,这里就涉及到了RTT,你要将需要检测的物体先渲染一遍,将法线信息保存到一张纹理中,然后通过采样对比每一点的法线和它周围的法线,从而得到结果。
具体步骤
1.RTT,将法线保存到一张纹理中。
2.使用一中的纹理,采用获得其中的法线数据,并将每一点的法线和它周围像素的法线点积,这样就可以得到一张描边的纹理了。
3.根据需求使用上边那张纹理。
具体实现:
步骤1的实现:
VertexOut VS(VertexIn vin)
{
VertexOut vout;
// 转换到投影空间
vout.PosH = mul(float4(vin.PosL, 1.0f), World);
vout.PosH = mul(vout.PosH, View);
vout.PosH = mul(vout.PosV, Proj);
vout.NormalV = mul(float4(vin.Normal,0.0f), WorldInvTransView).xyz;
return vout;
}
float4 PS(VertexOut pin) : SV_Target
{
pin.NormalV = normalize(pin.NormalV);
float4 normal = float4(pin.NormalV,0.0f);
return normal;
}
步骤2的实现:
vs就不写了,看你具体干什么了直接说ps:
float4 PS_EdgeDetect(VertexOut pin) : SV_Target
{
float3 normal = normalDepthTex.Sample(samNormalDepth, pin.Tex).xyz;
float sum = 0;
if (normal.x!=0.f&&normal.y!=0.f&&normal.z!=0.f)
{
for (int i = 0; i < 4; ++i)
{
sum += saturate(1 - dot(normal, normalDepthTex.Sample(samNormalDepth, pin.Tex + PixelKernel[i]).xyz));
}
}
return float4(sum, sum, sum, 0.0f);
}
大致就是这样,具体的需要根据具体需求去更改。
下面按照惯例上图: