3.顶点外扩方法实现的描边shader

描边shader的实现有很多种,顶点外扩是其中之一。顶点外扩的原理是用2个Pass 渲染物体2次

第一遍:描边,顶点沿法线方向外拓后用黑色渲染。外扩这一步的实现是在投影空间,也就是2D的,根绝法线的x和y值进行外扩,因为是沿着法线方向外扩,所以法线越和摄像机方向相同,也就是越接近面向摄像机的顶点,顶点的位置变化的越小,当法线和摄像机方向相同时,不会有任何变化。

第一遍渲染后,实际的图像如下:

3.顶点外扩方法实现的描边shader_第1张图片3.顶点外扩方法实现的描边shader_第2张图片

第二遍:正常渲染物体,与第一遍渲染的混合在一起

3.顶点外扩方法实现的描边shader_第3张图片3.顶点外扩方法实现的描边shader_第4张图片


优点:
(1)效果最好。
(2)适用范围广。
缺点:
(1)对效率有一定影响。因为有2个Pass,所以DrawCall为正常的2倍

(2)对于法线过度不均匀的模型,比如立方体,轮廓会有缝隙。


上边的立方体例子我是特意把描边的外扩值调到很大,便于理解。由第一遍渲染后的图和第二遍渲染后的图的对比,很容易理解这个方法的原理。其实就是通过法线来把边缘进行位移,如果不是边缘,则不位移,比如立方体的正面。在第二次渲染后,会覆盖同位置的像素,因为边缘已经外扩,像素的位置已经不是原来的位置,因此不会被覆盖,而像位于立方体正面的像素,则会被第二次渲染时覆盖,最后就混合成了带黑边的效果图。


Shader "Study/3_OutLine"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white"{}
	    _LineSize("OutlineSize", range(0, 0.1)) = 0.02
		_LineColor("LineColor", Color) = (0,0,0,1)
	}
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "Always" }
			// 先绘制这个纯色的顶点,然后在下一个pass绘制对象
			//这里不存在前后面,关闭裁剪前后面,也不需要深度缓存
			Cull Off // 关闭剔除,模型前后都会显示
			ZWrite Off // 系统默认是开的,要关闭。关闭深度缓存,后渲染的物体会根据ZTest的结果将自己渲染输出写入
			ZTest Always  // 深度测试[一直显示],被其他物体挡住后,此pass绘制的颜色会显示出来
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			float _LineSize;
			float4 _LineColor;
			struct v2f
			{
				float4 pos:SV_POSITION;
				float4 color : COLOR;
			};
			v2f vert(appdata_full v)
			{
				v2f o;
				// 获取模型的最终的投影坐标
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				// UNITY_MATRIX_IT_MV为【模型坐标-世界坐标-摄像机坐标】【专门针对法线的变换】
				// 法线乘以MV,将模型空间 转换 视图空间
				float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
				// 转换 视图空间 到 投影空间 【3D转2D】
				float2 offset = TransformViewToProjection(norm.xy);
				// 得到的offset,模型被挤的非常大,然后乘以倍率
				o.pos.xy += offset * _LineSize;
				o.color = _LineColor;
				return o;
			}
			float4 frag(v2f i) : COLOR
			{
				return i.color;
			}
			ENDCG
		}
		Pass
		{
			// 直接使用顶点和片段shader显示物体
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			sampler2D _MainTex;
			float4 _MainTex_ST;

			struct v2f 
			{
				float4 pos:SV_POSITION;
				float2 uv : TEXCOORD0;// 纹理,相对自身的坐标轴,float2是一个平面
			};
			v2f vert(appdata_full v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}
			float4 frag(v2f i) : COLOR
			{
				float4 texCol = tex2D(_MainTex, i.uv);
				return texCol;
			}
			ENDCG
		}
	}
}

附上工程连接:http://download.csdn.net/detail/yinfourever/9565336


你可能感兴趣的:(Shader学习,Unity,Shader,描边)