第八天 开始Unity Shader的学习之Blinn-Phong光照模型

Unity Shader的学习笔记

第八天 开始Unity Shader的学习之Blinn-Phong光照模型


文章目录


前言

今天我们编写另一种高光反射的实现方法 -- Blinn光照模型.同时了解一些Unity的内置函数.


提示:以下是本篇文章正文内容,下面案例可供参考

一、Blinn-Phong光照模型

Blinn模型没有使用反射方向,而是引入了新的矢量h,它是通过对视角方向v和光照方向l相加后在归一化得到的.公式如下:

Blinn模型计算高光反射的公式如下:

代码如下:

csharp 复制代码
Shader "Unity Shaders Book/Chapter 6/Blinn Phong"{
	Properties{
		_Diffuse ("Diffuse", Color) = (1, 1, 1, 1)
		_Specular ("Specular", Color) = (1, 1, 1, 1)
		//_Gloss用于控制高光反射属性
		_Gloss ("Gloss", Range(8.0, 256)) = 20
	}
	SubShader{
		Pass{
			Tags {"LightMode" = "ForwardBase"}

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag

			#include "Lighting.cginc"

			fixed4 _Diffuse;
			fixed4 _Specular;
			float _Gloss;

			struct a2v{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};

			struct v2f{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
			};

			v2f vert(a2v v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				//o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);  下面的代码和上面的是一个作用
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

				return o;
			}

			fixed4 frag(v2f i) : SV_Target{
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 worldNormal = normalize(i.worldNormal);
				//fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);  下面的代码和上面的是一个作用
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));

				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
																			①
				fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);
				fixed3 halfDir = normalize(viewDir + worldLightDir);
				fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(i.worldNormal, halfDir)), _Gloss);

				return fixed4(ambient + diffuse + specular, 1.0);
			}

			ENDCG
		}
	}
	Fallback "Specular"
}

①计算高光反射部分

首先我们还是计算出视角方向,然后再对视角方向和光照方向相加之后再归一化得到的,最后再计算高光部分即可.

效果展示

可以从效果图看出来,Blinn-Phong光照模型的高光反射部分看起来更大,更亮一点,在实际渲染中,绝大多数我们都会选择Blinn-Phong光照模型,但是这两种光照模型都是经验模型,换句话说,我们不应该认为Bliin_phong模型是对"正确的"Phong模型的近似,实际上,Blinn-Phong模型更符合实验结果.

二、召唤神龙:使用Unity内置的函数

我们在之前的Shader代码中,很多东西都是我们手动计算的,例如视角方向,光源方向等(虽然我们使用的_WorldSpaceLightPos0.xyz得到的光源方向只适合平行光,如果有更复杂的光源信息,这种方法就是错误的了),但是手动计算的过程比较麻烦,Unity提供一些内置函数来帮助我们计算这些信息.

函数名 描述
float3 WorldSpaceViewDir(float4 v) 输入一个模型空间中 的顶点位置,返回世界空间中从该点到摄像机的观察方向,内部实现使用了UnityWorldSpaceViewDir函数
float3 UnityWorldSpaceViewDir(float4 v) 输入一个世界空间中 的顶点位置,返回世界空间中从该点到摄像机的观察方向
float3 ObjectSpaceViewDir(float4 v) 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向
float3 WorldSpaceLightDir (float4 v) 仅可用于前向渲染中 ,输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向,内部使用了UnityWorldSpaceLightDir 函数,没有被归一化
UnityWorldSpaceLightDir (float4 v) 仅可用于前向渲染中 ,输入一个世界空间 中的顶点位置,返回世界空间中从该点到光源的光照方向,没有被归一化
float3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染中 ,输入一个模型空间 中的顶点位置,返回模型空间中从该点到光源的光照方向,没有被归一化
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从模型空间转换到世界空间中
float3 UnityObjectToWorldDir(float3 dir) 把方向矢量从模型空间变换到世界空间中
float3 UnityWorldToObjectDir(float3 dir) 把方向矢量从世界空间变换到模型空间中

类似于UnityXXXX的几个函数都是Unity5中新添加的内置函数,这些帮助函数使得我们不需要跟各种变换矩阵,内置变量打交道,也不需要考虑使用了哪种光源这种问题,而仅仅调用一个函数就可以得到需要的信息.

上面的9个帮助函数中,我们已经掌握了五个器内部实现,都在我们之前的代码中找到,但是需要注意的是,这些函数没有保证得到的方向矢量都是单位矢量,因此我们使用之前都需要将他们归一化.


总结

今天的内容就这么多,我们也可以进行一些尝试,将之前的计算使用这些函数代替一下.

相关推荐
secondyoung1 小时前
Cortex-R52学习:MPU内存保护机制
arm开发·单片机·学习·arm·mpu
red_redemption1 小时前
自由学习记录(198)
学习
花岛溯1 小时前
Cursor 学习 DAY2·切换AI模型
学习
星夜夏空991 小时前
FreeRTOS学习(9)——临界区
学习
小智老师PMP3 小时前
零基础能不能考PMP?零基础专属学习路径+全套扶持体系
学习·算法·职场和发展·软件工程·求职招聘·敏捷流程
XGeFei4 小时前
【Fastapi学习笔记(4)】—— JsonScheme与数据验证、错误响应格式、正则表达式
学习·fastapi
爱喝水的鱼丶5 小时前
SAP-ABAP:SAP 简单报表输出开发系列(共6篇) 第四篇:SAP 报表异常处理机制:数据校验与消息提示规范落地
开发语言·数据库·学习·算法·sap·abap
東雪木5 小时前
泛型、反射、注解(Spring 框架核心底层)专属复习笔记
java·windows·笔记·学习·spring
小陈phd6 小时前
多模态大模型学习笔记(四十七)——跨模态融合策略:早融合、中融合与晚融合核心解析
笔记·学习
进击的小头6 小时前
第7篇:MOS 管最全入门:原理、关键参数、选型、驱动与典型应用
经验分享·科技·嵌入式硬件·学习