在Unity Shader实现标准光照模型中的漫反射部分(逐像素)

Shader "Unity Shaders Book/Chapter 6/Diffuse Pixel-Level"
{
	Properties
	{
		_Diffuse ("Diffuse", Color)= (1, 1, 1, 1)//声明一个Color类型的属性,并把它初始值设为白色
	}
	SubShader{
		Pass{
			//LightMode标签是Pass标签的一种,它用于定义该Pass在Unity的光照流水线中的角色,
			//只有定义了正确的LightMode,我们才能得到一些Unity的内置光照变量
			Tags{ "LightMode"="ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			//包含进Unity的内置文件Lighting.cginc
			#include "Lighting.cginc"
			#include "UnityCG.cginc"

			//为了在Shader中使用Properties语义块中声明的属性,我们需要定义一个和该属性类型相匹配的变量
			//由于颜色属性的范围在0到1之间,因此我们可以使用fixed精度的变量来存储它
			fixed4 _Diffuse;//材质的漫反射颜色

			//定义顶点着色器的输入结构体
			struct a2v {
				float4 vertex : POSITION;
				float3 normal : NORMAL;//这里得到的法线是位于模型空间下的
			};
			//定义顶点着色器的输出结构体(输出结构体同时也是片元着色器的输入结构体)
			struct v2f {
				float4 pos : SV_POSITION; 
				//为了在顶点着色器中计算得到的光照颜色传递给片元着色器,我们在v2f中定义一个worldNormal变量
				float3 worldNormal : TEXCOORD0;
			};
			//顶点着色器不需要计算光照模型,只需要把世界空间下的法线传递给片元着色器即可
			v2f vert(a2v v){
				v2f o;
				//把顶点位置从模型空间转换到剪裁空间中,使用Unity内置的模型*世界*投影矩阵  UNITY_MATRIX_MVP  来完成这样的坐标转换
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				//v.normal : 顶点法线
				//_World2Object : 模型空间到世界空间的变换矩阵的逆矩阵
				//首先得到模型空间到世界空间的变换矩阵的逆矩阵_World2Object,然后通过调转它在mul函数中的位置,得到和转置矩阵相同的矩阵乘法。
				//由于法线是一个三维向量,因此我们只需要截取_World2Object的前三行前三列即可
				o.worldNormal = mul(v.normal, (float3x3)_World2Object);//得到世界空间下的法线(并未归一化)
				return o;
			}
			//片元着色器需要计算漫反射光照模型
			fixed4 frag(v2f i) : SV_Target{
				//通过Unity的内置变量UNITY_LIGHTMODEL_AMBIENT得到了环境光部分
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				fixed3 worldNormal = normalize(i.worldNormal);//得到归一化后的表面法线
				//需要注意的是,这里对光源方向的计算并不具有通用性。在本节中,我们假设场景中只有一个光源且光源的类型是平行光。但如
				//果场景中有多个光源并且类型可能是点光源等其他类型,直接使用_WorldSpaceLightPos0不能得到正确的结果
				fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);//归一化后的光源方向
				//saturate函数是CG提供的一种函数,它的作用是可以把参数截取到[0,1]的范围内,在这里使用这个函数防止点积的结果为负值
				//在计算法线和光源方向之间的点积,只有两者处于同一坐标空间下,它们的点积才有意义。在这里,我们把表面法线和光源方向都转换到世界空间
				//漫反射部分 = 光源颜色*材质的漫反射颜色*saturate(归一化的表面法线和归一化的光源方向的点积)
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
				fixed3 color = ambient + diffuse;
				return fixed4(color, 1.0);//输出顶点颜色
			}
			ENDCG
		}
	}
	Fallback "Diffuse"//把这个Unity Shader的回调shader设置为内置的Diffuse
}

来源于Unity Shader入门精要

与逐顶点光照相比,逐像素光照可以得到更加平滑的光照效果。但是,逐光照漫反射部分或是逐像素漫反射部分都存在一个问题。在光照无法到达的区域,模型的外观通常是全黑的,没有任何明暗变化,这会使模型的背光区域看起来就像一个平面一样,失去了模型细节表现。我们可以通过添加环境光来得到非全黑的效果。但即便是这样仍然无法解决背光面明暗一样的缺点。而半兰伯特(Half Lambert)光照模型因此被提出用于改善这个问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值