Unity入门精要04(0)-更复杂的光照
迪丽瓦拉
2025-05-29 19:04:55
0

本书知识点是真的多(

1.渲染路径

Unity中的渲染路径有如下选项 

   

对某一Pass指定了渲染路径后,Unity会在过程中自动填充系统的变量,便于使用。

1.1 前向渲染路径

   前向渲染的伪代码如下

一句话概括前向渲染就是:对于每个光源在其范围能影响物体的都计算一次所有的Pass(除了Base Pass以外),计算完光照后再把计算结果叠加起来。

但这如果在多光源的情况下会造成极大的性能消耗。因此Unity通常会自动进行光照质量的限制,

当然也可以自己设置

 

 在Render Mode处如果设置为Important,那么该光源就是逐像素光源。

详细参考可见  ↓↓↓

Forward rendering path - Unity 手册 (unity3d.com)

1.2 前向渲染的两种Pass

  

关于编译指令可参考

Declaring and using shader keywords in HLSL - Unity 手册 (unity3d.com)

使用这些编译指令可以产生Shader变种

 Base Pass 最基础的Pass,一个Base Pass只会进行一次平行光和其它所有的逐顶点和SH光

使用方法:在第一个Pass中加入

Tags { "LightMode"="ForwardBase" }
#pragma multi_compile_fwdbase//加入此编译命令,可以使之后光照衰减所使用的变量可以被正确赋值
//即能在BasePass中访问到正确的光照变量

 在第二个Pass中写下

Tags { "LightMode"="ForwardAdd" }
Blend One One//多光源叠加要开启混合,具体的混合操作可以看透明效果实现的那篇文章
#pragma multi_compile_fwdadd//此编译命令表示该Pass是用来进行多光源叠加的
//效果同上

Additional Pass,会计算影响该物体的所有逐像素光源,每个光源都进行一次Pass.

为了使Additional Pass 能和Base Pass进行混合,我们开启了混合命令,具体的混合命令请看《Unity入门精要》中的透明效果部分。

效果如下,我们设置绿色的为平行光,红色的为点光源

在帧调试器的时候,渲染顺序是调用Base先渲染平行光,然后调用Additional点光源远近依次渲染 

1.3 逐像素,SH光源和顶点照明(已经被抛弃)

  逐像素比较简单,略过,着重记录一下SH光源(魔方工作室的面试考到过)

球谐函数就是一组分布在球上的函数,这恰好可以描述光照在一个物体上的光照。 

详细参考:球谐光照——球谐函数 - 知乎 (zhihu.com)

2.延迟渲染。

如果游戏中有大量的实时光照,那么用前向渲染消耗会非常大,因为每个光照都会计算所有的Additional Pass,出大问题(

延迟渲染似乎只能在URP和SRP中使用?(不太清楚)

那么什么是延迟渲染?

延迟渲染分为两个Pass,第一个Pass通道用来将信息存储在G缓冲区(实际上就是输出到一张渲染纹理上)中

然后再第二个Pass进行计算光照和进行合成

可以把延迟渲染想象成一个拼图游戏。首先,你需要把所有的拼图碎片(物体)按照一定的规则(投影)放到一个大的画板(缓冲区)上,每个碎片都有自己的颜色、形状、质感等信息。这个过程叫做几何渲染(geometry rendering)。

然后,你需要把一些灯泡(光源)放到画板上,每个灯泡都有自己的颜色、亮度、方向等信息。这个过程叫做光照渲染(light rendering)。

最后,你需要把画板上的所有碎片和灯泡的信息混合起来,形成一个完整的拼图(图像)。这个过程叫做合成渲染(composition rendering)。

因此在实时光照和大量光照中延迟渲染性能更优。但延迟渲染也是有缺点的,例如

·不能支持真正的抗锯齿(因为延迟渲染使用了非常多的缓冲区来储存信息,而缓冲区的分辨率一般是和屏幕空间不同的,如果相同的话,缓冲区会占用非常多的带宽)

·不能处理半透明(因为延迟渲染相比于前向渲染是将光照计算放在三维物体投影到二维纹理之后进行光照计算。而我们在进行延迟渲染过程中是需要G-buffer,而G-buffer只能处理最前面的混合后的像素,不能记录半透明物体后面的像素)

·对显卡有一定要求,显卡必须支持MRT

延迟渲染的具体操作方法:使用两个Pass,第一个Pass用于渲染G_Buffer,用来储存漫反射颜色,高光反射颜色,自发光,平滑度,法线,深度,金属度等信息渲染到基于屏幕空间下的G缓冲区

 如图所示,更详细的可见

LearnOpenGL - Deferred Shading

 第二个Pass来计算光照,默认情况下只能用Standard 光照模型,如果要用其它的,就要替换掉原有的Internal-DeferredShaing.shader文件

延迟渲染可以访问的内置变量和函数

 3.光源类型

平行光,只有方向没有位置

点光源

聚光灯

面光源

4.光照衰减

  4.1光照衰减纹理

Unity内部使用了一张名为_LightTexture0的纹理来计算光源衰减。如果对光源使用了Cookie,那么衰减查找纹理是_LightTextureB0。

通俗来讲,这个纹理就是将光照衰减映射到纹理上,然后从(0,0)(离光源最近)依次查询到(1,1)(离光源最远)。为了知道物体上的某一点受到光照后的颜色究竟是什么?我们把物体上的所有顶点转换到光源空间下(这里就体现了Shader中的编程核心思想,要知道物体的样子,就是知道物体的颜色,要知道物体的颜色,就要根据光照模型计算,要获取光照模型中的相应参数,就应转换到相应的空间下去计算),在光源空间下查询光照衰减纹理

完整的光照衰减计算代码

#ifdef USING_DIRECTIONAL_LIGHTfixed atten = 1.0;
#else#if defined (POINT)//点光源float3 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1)).xyz;fixed atten = tex2D(_LightTexture0, dot(lightCoord,lightCoord).rr).UNITY_ATTEN_CHANNEL;//利用顶点在光源空间的中的距离的平方进行采样(避免开方)//利用宏UNITY_ATTEN_CHANNEL获取衰减纹理中(_LightTexture0)衰减值所在的分量#elif defined (SPOT)//聚光灯float4 lightCoord = mul(unity_WorldToLight, float4(i.worldPos, 1));fixed atten = (lightCoord.z > 0) * tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w * tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL;#elsefixed atten = 1.0;#endif
#endif

重点说明一下聚光灯(比较复杂) 

在聚光灯下_LightTextureB0是阴影纹理,_LightTexture0是储存光照强度和聚光灯颜色

1.

(lightCoord.z > 0) 这里的代码其实有歧义,因为在计算聚光灯光照的时候,我们通常采用的是锥形视锥,而不是平截头视锥,因为锥形视锥更适合表示聚光灯的光照区域。在锥形视锥中,视锥的顶点在 z 轴的负半轴上,因此 z 坐标始终是负数。而这里可能重新定义了朝向也说不定。所以这里开头是判断是否在视锥中(关于这个知识,可以去看Games101中的透视投影,每次投影的时候都需要将物体平移到原点,然后旋转相机为正(或者说是光源视锥)然后投影,然后再平移旋转返回原来的样子)

2. 

tex2D(_LightTexture0, lightCoord.xy / lightCoord.w + 0.5).w

第一个tex2D函数采样聚光灯的光强和颜色信息,lightCoord.xy / lightCoord.w 这里的含义是为了将其变为非齐次坐标变为齐次坐标,我们将物体的顶点从世界空间转换到光源的视锥空间的时候,因为矩阵乘法会给w赋上一定的权重,离视点越远,x,y,z越小,投影出来就会越小(这里需要理解齐次坐标的含义,我们将(x,y,z,w)叫做齐次坐标,它实际上表示的点应该为(x/w, y/w, z/w) 就是非齐次坐标,w中储存的是顶点的逆深度(1/z)),我们使用了转换矩阵转换到光源的视锥空间,然后又使用投影矩阵投影到二维上(因为纹理是二维的,可以形象的理解压缩成二维,贴在纹理上一个一个找),但是此时的x,y仍是齐次坐标,因此要除以w,消除w所带来的透视效果,变成原本的非齐次坐标。得到真正的二维坐标,而加上0.5则是保证映射到[0,1]上(纹理的范围)

那么为什么只取w分量呢?因为tex2D函数返回RGBA四个通道,我们取第4个通道,即透明度来表示光照衰减系数。

3. 

tex2D(_LightTextureB0, dot(lightCoord, lightCoord).rr).UNITY_ATTEN_CHANNEL

这个阴影贴图是根据光源空间中的深度信息计算得到的,因此需要将光源空间中的坐标进行 dot 运算得到深度值,然后取两个 R 分量构成 UV 坐标,用于采样阴影贴图纹理。这样做是因为阴影贴图可能采用不同的投影方式,如果不用 dot 运算来获取深度值并计算 UV 坐标,可能会导致阴影贴图采样出现错误。

最后使用宏UNITY_ATTEN_CHANNEL获取我们生产的衰减纹理中衰减值所在的分量

4.2 使用数学公式计算衰减

 

 

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...