Unity Shader-兰伯特光照模型与Diffuse Shader

本文深入探讨Unity中的兰伯特光照模型,从漫反射和镜面反射的基础概念出发,详细阐述逐顶点与逐像素计算的Diffuse Shader实现,并介绍半兰伯特光照模型及其纹理应用,结合TRANSFORM_TEX宏的应用,全面理解Unity图形渲染过程。
摘要由CSDN通过智能技术生成

简介


学了一段时间shader,然而一直在玩后处理,现在终于下定决心钻研一下真正的带光照的shader。从Diffuse到Specular。一个游戏的画面好坏,很大程度上取决于光照和贴图。现实世界中,我们之所以能看见东西,是因为他们要么反射了光源发出的光,要么是自身能够发光。而在游戏世界中,如果没有了光,我们虽然可以直接根据贴图显示物体的材质,但是少了很多细节光影效果,游戏显得不真实。但是,真实的光照计算是一个非常复杂的过程,对于游戏这种至少30FPS的程序来说是完全不可能的,所以我们必须要使用一种近似的光照算法,来模拟光照效果。本篇文章就来学习一下基本的光照模型以及其在unity下的shader实现。

漫反射和镜面反射


我们观察世界是因为有光进入我们的眼睛,光在世界中主要有反射和折射两种属性,当光照在某种介质表面时,一部分光发生反射,另一部分光进入介质,发生折射,也有转化为其他能量的光。本篇文章只讨论反射,折射等其他现象以后再学习。光的反射分为两种,漫反射和镜面反射。

漫反射,是投射在粗糙表面上的光向各个方向反射的现象。当一束平行的入射光线射到粗糙的表面时,表面会把光线向着四面八方反射,所以入射线虽然互相平行,由于各点的法线方向不一致,造成反射光线向不同的方向无规则地反射,这种反射称之为“漫反射”或“漫射”。这种反射的光称为漫射光。很多物体,如植物、墙壁、衣服等,其表面粗看起来似乎是平滑,但用放大镜仔细观察,就会看到其表面是凹凸不平的,所以本来是平行的太阳光被这些表面反射后,弥漫地射向不同方向。

镜面反射,是指若反射面比较光滑,当平行入射的光线射到这个反射面时,仍会平行地向一个方向反射出来,这种反射就属于镜面反射,其反射波的方向与反射平面的法线夹角(反射角),与入射波方向与该反射平面法线的夹角(入射角)相等,且入射波、反射波,及平面法线同处于一个平面内。


兰伯特光照模型


先来学习一个最简单的光照模型,兰伯特光照模型。兰伯特光照模型是目前最简单通用的模拟漫反射的光照模型,定义如下:模型表面的明亮度直接取决于光线向量(light vector)和表面法线(normal)两个向量将夹角的余弦值。光线向量是指这个点到光从哪个方向射入,表面法线则定义了这个表面的朝向。


如果漫反射光强设置为Diffuse,入射光光强为I,光方向和法线夹角为θ,那么兰伯特光照模型可以用下面的公式表示:Diffuse = I * cosθ
进一步地,我们可以通过点乘来求得两个方向向量之间的夹角,入射光方向设置为L,法线方向设置为N,如果光方向向量和法线方向向量都为单位向量(这就是为什么我们在写shader的时候需要normalize操作的原因),那么它们之间的夹角余弦值就可以表示为:cosθ = dot(L,N),最终漫反射光强公式,也就是兰伯特光照模型可以表示为:Diffuse = I  * dot(L,N)


逐顶点计算着色shader


我们在shader中需要计算输出的颜色,逐顶点着色也就是说我们的计算主要放在了vertex shader中,根据顶点来计算,每个顶点中计算出了该点的颜色,直接作为vertex shader的输出,pixel(fragment) shader的输入,当到达pixel阶段时,直接输出顶点shader的结果。比如一个三角形面片,在vertex阶段,分别计算了每个顶点的颜色值,在pixel阶段时,这个面片经过投影,最终显示在屏幕上的像素,会根据该像素周围的顶点来插值计算像素的最终颜色,这种着色方式也叫做 高洛德着色

下面看一下unity shader实现的逐顶点着色:
Shader "ApcShader/DiffusePerVetex"
{
	//属性
	Properties{
		_Diffuse("Diffuse", Color) = (1,1,1,1)
	}

	//子着色器	
	SubShader
	{
		Pass
		{
			//定义Tags
			Tags{ "RenderType" = "Opaque" }

			CGPROGRAM
			//引入头文件
	        #include "Lighting.cginc"
			//定义Properties中的变量
			fixed4 _Diffuse;
			//定义结构体:应用阶段到vertex shader阶段的数据,如果定义了
			struct a2v
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
			};
			//定义结构体:vertex shader阶段输出的内容
			struct v2f
			{
				float4 pos : SV_POSITION;
				fixed4 color : COLOR;
			};

			//定义顶点shader
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				//把法线转化到世界空间
				float3 worldNormal = mul(v.normal, (float3x3)_World2Object);
				//归一化法线
				worldNormal = normalize(worldNormal);
			
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值