王者荣耀角色光照

角色光照浅析

Posted by Bob on October 25, 2018

高光(Specular):模拟有光泽物体表面上的亮点,其颜色更倾向于光的颜色而不是物体表面的颜色。

Blinn-Phong specular 模型

vec3 viewDir;
vec3 halfDir = normalize(lightDir + viewDir);

//specPower 镜面高光系数
//I为入射光颜色向量,k为镜面反射系数

float  spec = I * k * pow(max(dot(halfDir, normal), gloss), specPower);

半角向量,用H表示。半角向量计算简单,通过将光源方向L和视线方向V相加后归一化即可得到半角向量.

image

Phong specular模型


vec3 viewDir;

//需要光线方向为由光源指出

vec3 reflectDir = normalize(reflect(-lightDir, normal)); 

//I为入射光颜色向量,k为镜面反射系数

float spec = I * k * pow(max(dot(reflectDir, viewDir), gloss), specPower); 

镜面反射强度跟反射向量与观察向量的余弦值呈指数关系,指数为gloss,该系数反映了物体表面的光滑程度。

image

1.该值越大,表示物体越光滑,反射光越集中。当偏离反射方向时,光线衰减程度越大,只有当视线方向与反射光方向非常接近时才能看到高光现象,镜面反射光形成的光斑较亮并且较小。

2.该值越小,表示物体越粗糙,反射光越分散,可以观察到光斑的区域越广,光斑大并且强度较弱。

计算由反射向量R和观察向量V决定,当两者的夹角a超过90时,截断为0.0,则没有了镜面光成分.

Phong specular模型能处理的是下面的左图中(a≤90)的情况,而对于右图中(a>90)的情况则镜面光成分计算为0

image

RimLight边缘发光:

image

在当前视角方向,物体上位于边缘的地方额外加一个光的效果。 通过法线方向和视线方向的夹角来判断,一个点是否在物体的边缘。

1.当视线方向V与法线方向N垂直时,这个法线对应的面就与视线方向平行,说明当前这个点对于当前视角来说,就处在边缘。dot(N,V)越接近0,此处有边缘光。

2.当视线方向V与法线方向N一致时,这个法线对应的面就垂直于视线方向,说明当前是直视这个面。dot(N,V)越接近1,边缘光越弱。

shader基本参数如下:

image


Shader "S_Game_Hero/Hero_Show_Rim_Dissolve"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}

		_RimColor("边缘光Rim Color",Color) = (1,1,1,1)
        _RimPower ("Rim Power",range(1,10)) = 2

		_MaskTex ("高光Mask (R,G,B)", 2D) = "white" {}
		_SpecColor ("Spec Color", Color) = (0,0,0,0)
		_SpecPower ("Spec Power", Range(1, 128)) = 15
		_SpecMultiplier ("Spec Multiplier", Float) = 1


		_LightTex ("轮廓光Light (RGB)", 2D) = "white" {}
		_LightColor ("Spec Color", Color) = (0,0,0,0)

		_HurtColor ("HurtColor", Color) = (0,0,0,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;
				float2  uv1:TEXCOORD1;
				float2  uv2:TEXCOORD2;	
				float2  uv3:TEXCOORD3;	

				UNITY_FOG_COORDS(1)
				float4 vertex : SV_POSITION;

				float3 angle : COLOR;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;

			sampler2D _MaskTex;
			float4 _MaskTex_ST;

			sampler2D _LightTex;
			float4 _LightTex_ST;

			float _RimPower;
			float4 _RimColor;
			
			float4 _SpecColor;
			float _SpecPower;
			float _SpecMultiplier;

			float4 _LightColor;
			float4 _HurtColor;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);

				
				float3  viewDir = UnityWorldSpaceViewDir(v.vertex);
				//视角方向从世界坐标到模型坐标的转换

				viewDir = mul((float3x3)unity_WorldToObject,viewDir);
				float3 vieNormal = normalize(viewDir);

				//用视角方向和法线方向做点乘,越边缘的地方,法线和视角方向越接近90度,点乘越接近0.

				o.angle.x = saturate(dot(v.normal,vieNormal));

				//平行光源的入射向量L 给个假的

				float3 lightDirection = normalize(float3(0.0, 0.0, 2.0));
				
				//镜面反射光的计算

				o.angle.y = max(0.0,dot(reflect(-lightDirection, v.normal),vieNormal));

				//UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// sample the texture

				fixed4 col = tex2D(_MainTex, i.uv) +  _HurtColor;

				//轮廓光

				fixed4 albedo = tex2D(_LightTex, i.uv) * _LightColor;
				col.rgb +=  albedo;

				//光泽度 值越高光泽度越高,1为极值,物极必反

				float gloss = tex2D(_MaskTex, i.uv.xy).x;
				//镜面反射 

				fixed3 reflectAngle = i.angle.y*0.5 + 0.5;
				//SpecColor高光

				col.rgb += _SpecColor * pow (reflectAngle, _SpecPower ) * gloss * _SpecMultiplier * 2.0;


                //用(1- 上面点乘的结果)*颜色,来反映边缘颜色情况

				float rim = 1 - i.angle.x;
				col.rgb += saturate(pow(rim ,_RimPower)*(1+_RimPower))* _RimColor.rgb;

				// apply fog

				//UNITY_APPLY_FOG(i.fogCoord, col);
				return col;
			}
			ENDCG
		}
	}
}


左图无光照,右图为处理过光照的模型渲染效果

image

参考资料:

Advanced Lighting