(四)光照计算模型模型

1.前言

所谓的光照效果,反映到屏幕上就是一个个像素问题,所以光照的计算公式就是计算的一个一个颜色值。这些公式基本属于经验公式范畴,只是让人看起来像真正的光效。
光分为环境光、自发光、漫反射以及高光反射,反映到像素上就是颜色的叠加。即最终在片元着色器中返回的颜色值=环境光颜色+自发光颜色+漫反射颜色+高光反射颜色。下面依次对这些光进行说明。

2.环境光Ambient

环境光在Unity中可以设置,即windows-lighting中即可看到,在2018中则是window-rendering-lightingsettings中设置。在shader中通过如下变量可以获取到:UNITY_LIGHTMODEL_AMBIENT。但是一般计算中我们只需要颜色的rgb值。

3.自发光Emissive

自发光是最简单的,直接简单粗暴的暴露一个颜色值,包此值当作自发光颜色。

4.漫反射diffuse

漫反射计算参考一下光照模型进行计算。

4.1 兰伯特定律LambertLaw

兰伯特定律认为反射光线跟光源方向与法线夹角有关系(夹角余弦值),所以漫反射计算公式如下:
漫反射颜色 = 光源颜色 x 材质的漫反射颜色 x Max(0,Dot(法线,指向光源的方向)
其中:
光源颜色:变量_LightColor0代表光源颜色。
材质漫反射颜色:自定义的颜色值。
法线:可以获取到每个顶点的法线,计算式采用单位向量。
光源方向:指从当前位置到光源的方向,计算式采用单位向量。
由于实际中当法线与光源方向夹角大于90°时,已经不会有反射效果,此时两者余弦值为负值,所以此时应该取0。

4.1.1 逐顶点计算

逐顶点计算漫反射时,在顶点着色器中计算,此时计算量小,但是效果差。在计算世界坐标系下的法线时,采用如下所示:

    //获取法线(统一到世界坐标系下),不做归一化效果要优于归一化。
    //fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
    fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);

上述注释掉的方法也是UnityObjectToWorldNormal方法,当然UnityCG种方法比注释掉的方法复杂一点。完整代码如下:

Shader "LL/Light/DiffuseVertex_Lambert"
{
   
	Properties
	{
   
		_Diffuse ("Diffuse", Color) = (1,1,1,1)
	}
	SubShader
	{
   
		Tags {
    "LightMode"="ForwardBase" }

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


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

			struct v2f
			{
   
				float4 position : SV_POSITION;
				float3 color : COLOR;
			};

			fixed4 _Diffuse;
			
			v2f vert (a2v v)
			{
   
				v2f o;
				o.position = UnityObjectToClipPos(v.vertex);
                //获取环境光
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				//获取法线(统一到世界坐标系下)。
				//fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
				//fixed3 worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
				//fixed3 worldNormal = mul((float3x3)unity_ObjectToWorld, v.normal);
				//获取环境光方向
				fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
				//计算漫反射强度
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
				//总强度叠加效果
				o.color = ambient + diffuse;
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
   
				return fixed4(i.color,1);
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
}

注:在计算光源方向时,应该是光源方向应该是光源位置减顶点位置,但是在真正计算时考虑不同情况,计算方式不同,UnityCG中也存在计算方法,直接用光源位置是一种情况,本文是示例,所以只采用最简单的方法。

4.1.2 逐片元计算

逐片元计算方法与顶点计算方法一致,只是在片元着色器中进行颜色计算,在顶点着色器中将法线传递过来即可,如下所示:

Shader "LL/Light/DiffuseFragment_Lambert"
{
   
	Properties
	{
   
		_Diffuse ("Diffuse", Color) = (1,1,1,1)
	}
	SubShader
	{
   
		Tags {
    "LightMode"="ForwardBase" }

		Pass
		{
   
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"
			
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值