天天看点

unity3d 之 边缘光(rim)

边缘光在游戏中是很常用到的,比如角色受到攻击,模型边缘会有一圈红色的边框,这些都是边缘光得到的奇妙效果。下图展现了边缘光的效果

unity3d 之 边缘光(rim)

边缘关的原理如下图所示

unity3d 之 边缘光(rim)

代码如下图

Shader "Custom/Rim" {
	Properties {
	   //对边缘光做一个衰减
	   _Scale("RIM_SCALE", range(1, 8)) = 2
	}
	SubShader {
	
		pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "unitycg.cginc"
		   
		    float _Scale;
		    struct v2f{
		    	float4 pos: SV_POSITION;
		    	float3 normal: TEXCOORD0;
		    	float4 vertex: TEXCOORD1;
		    };
		   
		   //收集模型法线和顶点,并返回
		    v2f vert(appdata_base v){
		    	v2f vf;
		    	vf.pos = mul(UNITY_MATRIX_MVP, v.vertex);
		    	vf.normal = v.normal;
		    	vf.vertex = v.vertex;
		    	return vf;
		    }
		    
		    fixed4 frag(v2f IN):color{
		        //下面的两个函数都是unitycg.cginc的,
		        //UnityObjectToWorldNorm  作用是把 法线 转到 世界空间
		    	float3 N = UnityObjectToWorldNorm(IN.normal);
		    	//WorldSpaceViewDir 作用是计算相机到物体定点的向量
		    	float3 V = WorldSpaceViewDir(IN.vertex);
		    	V=normalize(V);
		    	//计算边缘光
		     	float bright = 1 - saturate(dot(N, V));
		     	//衰减计算
		     	bright = pow(bright, _Scale);
		     	//返回固定色
		     	return fixed4(1,1,1,1) * bright;
		    }
			ENDCG
		}
	} 
}
           

然后可以通过简单的代码进行shader的切换,进行模拟角色被攻击的效果 (略)

可能还有这样一个情景,当角色受到攻击的时候,不仅要边缘高光,而且可以从身体看穿,看到身后的物体,这样可以增加真实感。这里实现这个其实很简单 (如下效果)

unity3d 之 边缘光(rim)

左边的是边缘光带透明的,右边是只有边缘光的  代码如下,只需要加入简单的混合方式和 队列顺序

Shader "Custom/Rim_tranpernet" {
	Properties {
	   _Scale("RIM_SCALE", range(1, 8)) = 2
	}
	SubShader {
	    //渲染队列为透明
		tags {"Queue" = "Transparent"}
		pass{
		    //混合方式
			Blend SrcAlpha oneMinusSrcAlpha
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "unitycg.cginc"
		     
		    float _Scale;
		    struct v2f{
		    	float4 pos: SV_POSITION;
		    	float3 normal: TEXCOORD0;
		    	float4 vertex: TEXCOORD1;
		    };
		   
		    v2f vert(appdata_base v){
		    	v2f vf;
		    	vf.pos = mul(UNITY_MATRIX_MVP, v.vertex);
		    	vf.normal = v.normal;
		    	vf.vertex = v.vertex;
		    	return vf;
		    }
		    
		    fixed4 frag(v2f IN):color{
		    	float3 N = UnityObjectToWorldNorm(IN.normal);
		    	float3 V = WorldSpaceViewDir(IN.vertex);
		    	V=normalize(V);
		    	
		     	float bright = 1 - saturate(dot(N, V));
		     	bright = pow(bright, _Scale);
		     	return fixed4(1,1,1,1) * bright;
		    }
	 
			ENDCG
		}
	} 
}
           
U3D