untiy 利用法线做高效3D模型 边缘泛光

在unity3D项目中,当选中一个3d模型,需要对其做一个外观的变化,来表现一个交互。
经常是以描边或边缘泛光的形式来处理。

描边的效果经常都是通过两个PASS来实现的,1个输出 沿着法线发现 放大的模型,再统一着色,这个颜色就是描边的颜色。另一个则直接输出。由于第一个沿着法线有做放大,所以就能实现描边的效果。

而边缘泛光则只需要一个PASS解决。当然效果有点区别,这个看需求而定。

思路:核心就是边缘检测,通过视向量和顶点的法向量的点积来实现。当两个向量的夹角越大,越靠近边缘。依赖这个做颜色强度,和纹理颜色做差值运算 就可以了。

没有边缘泛光效果
untiy 利用法线做高效3D模型 边缘泛光_第1张图片
加上内边缘泛光效果
untiy 利用法线做高效3D模型 边缘泛光_第2张图片
shader代码:

Shader "JackyShader/OutLineShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_OutLineColor("OutLineShader",Color) = (0.0,0.0,0.0,1.0)
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : NORMAL;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;
				float4 pos : POSITION1;
				fixed3 normal : NORMAL;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			fixed4 _OutLineColor;
			
			v2f vert (appdata v)
			{
				v2f o;
				//顶点变换到view空间
				o.vertex = UnityObjectToClipPos(v.vertex);
				//传入object空间的 顶点和法线
				o.pos = v.vertex;
				o.normal = v.normal;
				//计算UV
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				//纹理采样
				fixed4 col = tex2D(_MainTex, i.uv);
				//将法线变换到world空间 UnityObjectToWorldNormal方法随便做了规范化
				float3 normal = UnityObjectToWorldNormal(i.normal);
				//将顶点变换到world空间
				float3 wpos = mul(unity_ObjectToWorld,i.pos).xyz;
				//计算视向量 则摄像机到顶点的向量
				float3 viewDir = UnityWorldSpaceViewDir(wpos);
				//规范成单位向量
				viewDir = normalize(viewDir);
				//点积dot 来检测边缘 当视向量和法向量 夹角为90度时 则为边缘
				//cos(90)= 0 ,1 - cos(a) 则当夹角越大是 br越大
				float br = 1 - saturate(dot(normal,viewDir));
				//这里做一个指数运算,目的是为了加剧角度渐变
				br = pow(br,3.0);
				//当前颜色和边缘色做差值运算
				col = lerp(col,_OutLineColor,br);
				UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}

br = pow(br,3.0);这里的数值可以使用外部变量来控制边缘区域的大小。

其他的代码注释已经非常详细了,我这里就不做太多讲解。

你可能感兴趣的:(untiy 利用法线做高效3D模型 边缘泛光)