Unity中对物体进行轮廓线描绘的几种实现方案及原理

1.基于屏幕后处理

A.利用CommandBuffer

m_CommandBuffer.SetGlobalColor("_ID", col);//向pass 0中传颜色
m_CommandBuffer.DrawRenderer(r, m_OutlineMaterial, i, 0);
// Pass 0: Fill id
Pass
{
	Cull Off

	CGPROGRAM
	#pragma vertex vertex
	#pragma fragment fragment			
	#pragma enable_d3d11_debug_symbols
	#include "UnityCG.cginc"

	sampler2D _MainTex;
	sampler2D _Tex;
	fixed4 _ID;

	fixed4 fragment(v2f i) : SV_Target
	{
		fixed4 col = tex2D(_MainTex, i.uv);			
		if (col.a < 0.1) discard;
		return _ID;
	}
	ENDCG
}

col为每个模型(或mesh)对应的颜色,每个模型颜色都不同
DrawRenderer的顺序决定了渲染顺序,进而影响边的位置

B.在OnRenderImage执行CommandBuffer 绘会模型颜色区

Unity中对物体进行轮廓线描绘的几种实现方案及原理_第1张图片

C.pass 1中进行边缘检测,非边缘区全部置为白色

Unity中对物体进行轮廓线描绘的几种实现方案及原理_第2张图片

D.pass 2中进行模糊处理,包含横向和纵向

Unity中对物体进行轮廓线描绘的几种实现方案及原理_第3张图片

E.将C和D的RenderTexture传递给pass 3

C中黑色部分,且D中非黑色部分,设置为边的颜色
C中白色部分,为填充色

此方法对多个mesh组成的模型需要特殊处理,即将同模型的_ID值置为相同的值,否则会导致每个mesh都被描边,而不是仅轮廓线。

2.基于顶点着色器顶点修改

A.给模型添加新的材质球

B.pass 0进行模板测试,将模型像素区的模板缓存置为1

C.pass 1将模型顶点延法线法线外扩,且进行模板测试,不为1的像素模板测试通过,为1的过滤掉。

  • 此方法对互相遮蔽的模型,会导致轮廓线“看起来”融合到一起,主要是因为被遮蔽的模型的轮廓线会被前面的模型的模板测试留下的模板缓冲区的值给过滤掉

解决方案:

1.将各个模型排序,从近到远,分别向Shader中传入Stencil Ref的值,从大到小;越近的值越大,Stencil Buffer默认值是0。如图所示,这里需要将2个pass拆分为2个Shader。
Unity中对物体进行轮廓线描绘的几种实现方案及原理_第4张图片
2.第一个Shader(即原来的pass 0)的render queque使用大于2500的值,保证back-to-font的渲染顺序。
3.第二个Shader(即原来的pass 1)的模板测试Compare Func改为 Greater,即传入Ref的值>Stencilbuffer中的值,像素通过测试。
4.此方法当模型位置变动时,Stencil的值需要实时更新

你可能感兴趣的:(Unity,Shader)