Unity中利用Shader实现漫反射光照模型

Unity中利用Shader实现漫反射光照模型

逐顶点光照

逐顶点光照计算是在顶点着色器函数内计算完成的,计算每个顶点的颜色输出给片段着色器进行插值计算,漫反射光照模型计算公式:
C d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) m a x ( 0 , n ⃗ ⋅ l ⃗ ) C_{diffuse}=(c_{light} ⋅m_{diffuse})max(0,\vec{n} ⋅\vec{l}) Cdiffuse=(clightmdiffuse)max(0,n l )

其中, c l i g h t c_{light} clight:入射光线的颜色。 m d i f f u s e m_{diffuse} mdiffuse:材质的漫反射颜色, n ⃗ \vec{n} n :表面法线, l ⃗ \vec{l} l :光源方向(指向光源)。

Shader "myShaderTest/DiffuseVertex"
{
    Properties
    {
		_Diffuse("Diffuse",Color) = (1,1,1,1)
    }
    SubShader
    {
        Pass
        {
			//在Pass第一行指定渲染光照模式
			//Tags{"Lightmode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			//引用Unity内置文件,需要用到一些内置变量
            #include "UnityCG.cginc"
			#include "Lighting.cginc" 
			//定义与Properties中匹配的变量
			fixed4 _Diffuse;
			//顶点着色器输入,顶点和法线
			struct a2v {
				//模型坐标系坐标位置
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
            //片元着色器输入,裁剪坐标系下顶点位置和颜色
			struct v2f {
				//裁剪坐标系顶点位置
				float4 pos : SV_POSITION;
				float3 color : COLOR;
			};
			//顶点着色器,输入为模型顶点和法线,输出返回v2f结构体
			v2f vert(a2v v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				//得到环境光颜色
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
				//将模型法线坐标系转换为世界坐标系
				fixed3 worldNormal = normalize(mul(v.normal, (float3x3)unity_WorldToObject));
				//获得世界坐标系的灯光方向
				fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
				//计算反射光线
				fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));
				o.color = ambient + diffuse;
				//o.color = diffuse;
				return o;
			}
			//片元着色器,输入为顶点着色器输出值
			fixed4 frag(v2f i) :SV_Target{
				//直接返回计算的顶点颜色
				return fixed4(i.color,1.0);
			}
            ENDCG
        }
    }
		FallBack "Diffuse"
}

逐像素光照

逐像素光照计算是在片元着色器函数中实现的,可以使模型表面光线过度更加平滑。

	struct a2v {
		//模型坐标系坐标位置
		float4 vertex : POSITION;
		float3 normal : NORMAL;
	};
	//片元着色器输入,裁剪坐标系下顶点位置和颜色
	struct v2f {
		//裁剪坐标系顶点位置
		float4 pos : SV_POSITION;
		float3 worldNormal : TEXCOORD0;
	};
	//顶点着色器,输入为模型顶点和法线,输出返回v2f结构体
	v2f vert(a2v v) {
		v2f o;
		o.pos = UnityObjectToClipPos(v.vertex);
		//将模型法线坐标系转换为世界坐标系
		o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
		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 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir));
		fixed3 color = ambient + diffuse;
		return fixed4(color,1.0);
	}

半兰伯特模型

C d i f f u s e = ( c l i g h t ⋅ m d i f f u s e ) ( 0.5 ( n ⃗ ⋅ l ⃗ ) + 0.5 ) C_{diffuse}=(c_{light} ⋅m_{diffuse})(0.5(\vec{n} ⋅\vec{l})+0.5) Cdiffuse=(clightmdiffuse)(0.5(n l )+0.5)
兰伯特漫反射模型在光线无法照到的表面一片漆黑,半兰伯特模型背光面也有明暗变化。

//片元着色器,输入为顶点着色器输出值
	fixed4 frag(v2f i) :SV_Target{
		fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
		fixed3 worldNormal = normalize(i.worldNormal);
		fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
		fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightDir)*0.5+0.5);
		fixed3 color = ambient + diffuse;
		return fixed4(color,1.0);
	}

如下分别为逐顶点兰伯特、逐像素兰伯特、逐像素半兰伯特效果图。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智能驾驶小管家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值