实践篇:光的反射实现原理

前言:本篇博客只是一个简单的了解光的反射实现原理的例子,主要是当做笔记使用。

核心要点:如下所示:
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
		}
	}
}

运行效果:如下所示:
在这里插入图片描述

发布了81 篇原创文章 · 获赞 39 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/zjz520yy/article/details/95202751
今日推荐