边缘检测有很多方法,这里讲的是基于法线的边缘检测。

需要的知识有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);
}

大致就是这样,具体的需要根据具体需求去更改。

下面按照惯例上图:

edge_detect


ShiweyYan

A game developer who graduates from SCUT.