Unity Shader 学习笔记(15) 立方体纹理、反射、折射、菲涅尔反射

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l773575310/article/details/78583264

Unity Shader 学习笔记(15) 立方体纹理、反射、折射、菲涅尔反射

参考书籍:《Unity Shader 入门精要》


立方体纹理(Cubemap)

是环境映射(Environment Mapping)的一种实现方法。用于模拟物体周围的环境,使用了环境映射的物体可以让物体像镜子一样反射周围环境。

采样方法:用一个三维纹理坐标表示方向,原点是立方体中心。交点就是采样的结果。
在这里插入图片描述

天空盒子(Skybox)

用于模拟室内背景。

创建环境映射的立方体纹理方法有三种:

  • 由特殊布局的纹理创建。提供如立方体展开图的交叉布局、全景布局等。
  • 创建一个Cubemap,把6张纹理拖拽到面板中。
  • 由脚本生成,可以从任意位置观察场景的图像存储到6张图像中。调用Camera.RenderToCubemap(cubemap)生成,创建cubemap要标记Readable才能修改。

反射(Reflection)

用环境映射纹理代替了高光反射。
在这里插入图片描述

Properties {
	_Color ("Color Tint", Color) = (1, 1, 1, 1)
	_ReflectColor ("Reflection Color", Color) = (1, 1, 1, 1)	// 反射颜色
	_ReflectAmount ("Reflect Amount", Range(0, 1)) = 1			// 反射程度
	_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}		// 环境纹理
}
struct v2f {
	...
	fixed3 worldViewDir : TEXCOORD2;
	fixed3 worldRefl : TEXCOORD3;
	SHADOW_COORDS(4)
};

v2f vert(a2v v) {
	v2f o;
	...
	
	o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);	//计算视角方向
	o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);	// 计算反射方向
	
	TRANSFER_SHADOW(o);
	return o;
}

fixed4 frag(v2f i) : SV_Target {
	...
	
	// 对立方体采样,CG的texCUBE函数。
	fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb * _ReflectColor.rgb;
	
	UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
	
	// 对漫反射和立方体做插值,作为漫反射和高光反射的颜色。
	fixed3 color = ambient + lerp(diffuse, reflection, _ReflectAmount) * atten;
	
	return fixed4(color, 1.0);
}



折射(Refraction)

斯涅耳定律(Snell’s Law),n为折射率:

  • n1sinθ1 = n2sinθ2
    在这里插入图片描述

在实际中,需要计算两次折射,第一次是光线进入内部,第二次是内部射出。但要在实时渲染时模拟第二次折射比较复杂,所以通常只模拟第一次折射。
在这里插入图片描述

Properties {
	_Color ("Color Tint", Color) = (1, 1, 1, 1)
	_RefractColor ("Refraction Color", Color) = (1, 1, 1, 1)		// 折射颜色
	_RefractAmount ("Refraction Amount", Range(0, 1)) = 1			// 折射程度
	_RefractRatio ("Refraction Ratio", Range(0.1, 1)) = 0.5			// 折射比例
	_Cubemap ("Refraction Cubemap", Cube) = "_Skybox" {}			// 模拟折射环境纹理
}
v2f vert(a2v v) {
	v2f o;
	...
	
	o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
	// 计算折射方向,第一个参数为入射方向,第二个参数是表面法线,第三个参数是入射折射率和出射比值。
	o.worldRefr = refract(-normalize(o.worldViewDir), normalize(o.worldNormal), _RefractRatio);
	
	TRANSFER_SHADOW(o);
	return o;
}

fixed4 frag(v2f i) : SV_Target {
	...
	// 对立方体采样
	fixed3 refraction = texCUBE(_Cubemap, i.worldRefr).rgb * _RefractColor.rgb;
	
	UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
	
	// 混合漫反射颜色和折射颜色
	fixed3 color = ambient + lerp(diffuse, refraction, _RefractAmount) * atten;
	return fixed4(color, 1.0);
}

菲涅尔反射(Fresnel reflection)

即光线照射物体时,一部分发生反射,另一部分进入物体发生折射或散射。

近处湖面可以直接看到湖底(折射),远处湖面就只能看到镜面反射了。

Schilick菲涅尔近似等式(F0为反射系数,v为视角方向,n为表面法线):
在这里插入图片描述

Empricial菲涅尔近似等式:
在这里插入图片描述

使用Schilick菲涅尔近似等式实现:

Properties {
	_Color ("Color Tint", Color) = (1, 1, 1, 1)
	_FresnelScale ("Fresnel Scale", Range(0, 1)) = 0.5	// 对应F0
	_Cubemap ("Reflection Cubemap", Cube) = "_Skybox" {}
}
v2f vert(a2v v) {
	v2f o;
	...
	// 同反射计算
	o.worldViewDir = UnityWorldSpaceViewDir(o.worldPos);
	o.worldRefl = reflect(-o.worldViewDir, o.worldNormal);
	
	TRANSFER_SHADOW(o);
	return o;
}

fixed4 frag(v2f i) : SV_Target {
	...
	
	fixed3 reflection = texCUBE(_Cubemap, i.worldRefl).rgb;
	
	// Schlick菲涅尔近似等式
	fixed fresnel = _FresnelScale + (1 - _FresnelScale) * pow(1 - dot(worldViewDir, worldNormal), 5);
	
	fixed3 color = ambient + lerp(diffuse, reflection, saturate(fresnel)) * atten;
	
	return fixed4(color, 1.0);
}

普通反射和菲涅尔反射系数都为 0 对比:
在这里插入图片描述

普通反射和菲涅尔反射系数都为 0.2 对比:
在这里插入图片描述

普通反射和菲涅尔反射系数都为 1 对比(通过公式可以看出两者值是一样的):
在这里插入图片描述

没有更多推荐了,返回首页