實踐篇:光的反射實現原理

前言:本篇博客只是一個簡單的瞭解光的反射實現原理的例子,主要是當做筆記使用。

核心要點:如下所示:
1.光的折射原理主要依賴於斯涅爾定義。如下所示:
在這裏插入圖片描述
2.光的反射原理主要依賴於菲涅爾定義。由於其過於複雜,一般使用菲涅爾近似值來表示。如下所示:
在這裏插入圖片描述
核心代碼:如下所示:

Shader "Unlit/FresnelShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		// fresnel偏移量
		_FresnelOffset("FresnelOffset", Range(0, 1)) = 0
		// fresnel縮放量
		_FresnelScale("FresnelScale", Range(0, 1)) = 0
		// fresnel開方係數
		_FresnelPow("FresnelPow", Range(1, 5)) = 1
		// 折射光顏色
		_RefractionCol("RefractionCol", Color) = (1, 1, 1, 1)
	}
	SubShader
	{
		Tags { "RenderType"="Opaque" }
		LOD 100

		Pass
		{
			Tags { "lightmodel"="forwardbase" }

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			#include "Lighting.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				// 模型空間中的法向量
				float3 normal:NORMAL;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
				// 世界空間中的法向量
				float3 N:TEXCOORD1;
				// 世界空間中的光向量
				float3 L:TEXCOORD2;
				// 世界空間中的視向量(頂點指向攝像機的向量)
				float3 V:TEXCOORD3;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _FresnelOffset, _FresnelScale, _FresnelPow;
			float4 _RefractionCol;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				// 獲取世界空間中歸一化的法向量:使用模型到世界矩陣的逆矩陣的轉置矩陣對模型空間的法向量進行變換得到
				o.N = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
				// 獲取世界空間中歸一化的光照向量:頂點指向光源的方向
				o.L = normalize(WorldSpaceLightDir(v.vertex));
				// 獲取世界空間中歸一化的視向量:頂點指向攝像機的方向
				o.V = normalize(WorldSpaceViewDir(v.vertex));

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				// 對主紋理進行採樣來得到採樣顏色值
				fixed4 col = tex2D(_MainTex, i.uv);
				// 獲取法向量和光照向量點積值,用來表示光照強度,且點積值爲負值表示光照在物體背面,可以不用考慮
				float atten = saturate(dot(i.N, i.L));
				// 獲取漫反射顏色:光照顏色乘以光照強度
				fixed4 diffuse = _LightColor0 * atten;
				// 對主紋理顏色按照漫反射進行處理
				col.rgb *= diffuse.rgb;

				// 獲取菲涅爾近似值:菲涅爾偏移值 + 菲涅爾縮放值 * pow(1 + dot(法向量, 光向量(也就是攝像機指向頂點的向量)), 開方係數)
				// 當法向量與光向量的夾角越小,菲涅爾近似值就越小,表明反射越小,否則就是越大。
				float fresnel = _FresnelOffset + _FresnelScale * pow(1 - dot(i.N, i.V), _FresnelPow);
				// 將反射光和折射光進行混合:finialCol = lerp(反射光,折射光,菲涅爾近似值)
				col.rgb = lerp(col.rgb, _RefractionCol, fresnel);

				return col;
			}
			ENDCG
		}
	}
}

運行效果:如下所示:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章