我弃用了excel制作笔记
之前参加“游戏的人”这个交流活动的时候,听一个策划大佬说用excel做笔记和策划案很方便。经过近半年的excel笔记经验,一开始觉得确实还不错,但后来接触了md,发现excel就是个垃圾!之后的笔记都会转md了。
带有Part*字样的笔记文件,转移和保存时务必找齐所有部分
减少不透明物体重叠部分的渲染的无用计算。
- 上面的描述是正确的,以下做一些补充说明。
- 发生的具体时间是光栅化(三角形遍历)之后、片元着色器之前。
- 在Early-Z这一步,可以嵌套模板测试。但是没说具体怎么加。
- Early-Z在以下情况下会失效(我不知道这个“失效”具体是怎样的,是效果错误?还是在硬件层面直接自动跳过这一步?课程没有说清楚。)
- 开启透明度测试。透明度测试不能嵌套在Early-Z中,如果片元通过了Early-Z,片元的深度就会被写到缓冲区,如果又在后续的透明度测试中被Cull,就会导致片元没了,但深度还在缓冲区中,这样的话,这些片元没了的区域要如何渲染?这会导致一些未知错误。曾经在联想实习、制作可旋转Launcher时,使用了大量半透明材质,好像就导致了一些区域片元没了,然后渲出来那一块极其亮。我不知道是否是这个问题。
- 在片元着色器中使用Clip或者Discard。这两个函数涉及片元的舍弃,会导致和1一样的问题。
- 手动修改片元深度。我甚至不知道片元的深度是可以修改的。
- 开启Alpha Blend。即半透明物体的Shader,半透明物体一般关闭深度写入,这会导致Early-Z的深度写入也关闭。有没有更深的影响(比如直接导致硬件禁用Early-Z),课程没说清楚。
- 直接关闭深度测试。会导致Early-Z也直接不进行。
- Early-Z只能节省Over Draw部分的片元着色器的性能(对于不透明物体,Over Draw部分的渲染在片元着色器前被掐断),并不能对Over Draw问题本身做任何改善。所以还是需要做好渲染队列、同队列渲染顺序排列等优化。
- 思路是,先通过一个Pass仅做深度测试和深度写入,再用另一个pass计算着色。
- 会导致多Pass和无法动态批处理的问题(多Pass Shader无法动态批处理)。在URP中,这个问题可以用自定义的Render Feature改善。如果想进一步了解,搜索“雨松MOMO“的博客。
- Z-Prepass仅在重叠部分特别多、且Early-Z不能用的时候使用,收益才比较大,否则可能导致负收益。
这课主要讲硬件,我对此非常陌生,几乎没听懂。“前期囫囵吞枣”,总之先记下一些常识性的东西吧。
高通旗下的Adreno和Mail几乎对半开,一共占总体使用的97%以上,剩下的2%左右几乎都是PowerVR-GPU。
台式电脑:300w
游戏本:150w
主流笔记本:50~60w
旗舰平板电脑:8~15w
旗舰手机:5~8w
主流手机:3~5w
可见移动平台的功耗要求非常高,这也是移动端GPU架构和桌面端不同的直接原因。
System On Chip、片上系统。类似于一块大芯片。上面焊死了CPU、GPU、内存、通信基带、GPS芯片等等。
先说IMR,IMR是Immediate Mode Rendering、立即渲染,就是广义上的PC的渲染方式,参照入门精要笔记中的渲染流水线的三大步,基本流程如下图。
TBDR、Tile Based Deferred Rendering,基于分块的阻塞渲染,是目前大多数移动端使用的渲染架构,流程如下图:
上图中的VS是Vertex Shader、顶点着色器;RS是Rasterization、光栅化;PS是Pixel Shader、像素着色器 片元着色器。
目前大部分移动端使用的都是TBDR渲染架构。
TBDR总体来说分为两个阶段:
- **分Tile给予图元列表、做几何变换。**在入门精要里提过IMR的Draw Call,直接用一个图元列表;但是TBDR需要多个图元列表,每个Tile一个,如果一个图元在多个Tile中存在,那么这几个图元列表中都应该包含这个图元。
- **光栅化开始到输出到Buffer。**字面意思。
下图对应TBDR的基本流程,上述1的内容主要在Tiler中。这么做主要是为了利用上面提到的比较小的On-Chip Memory,它虽然小但是比较近,可以节省很多带宽(毕竟一次只渲染一小块),进而节省很多功耗,也正是因为小,所以必须分块渲染,这会导致渲染较慢。
优点:
- 提前遮挡剔除做得比较好。类似上节课的Early-Z,硬件层面这块做得比较好。
- 对带宽要求低,省电。
缺点:
- 观察上面的流程图,在Tiler步骤后图元数据被写入内存中,然后再从内存中读取后进入下一步计算。这导致顶点着色器之后、片元着色器之前的步骤开销会变大,曲面细分、几何着色器不再好用。同时,若几何数据过多,易造成性能瓶颈(这句没理解)。
- 上面提到的分Tile中,如果一个图元在多个Tile中存在,那么这几个图元列表中都应该包含这个图元,这其实是一种浪费。
- 慢,肯定不如IMR快。
如果开发移动端项目,遵循以下规则吧。
-
**大部分IMR可使用的优化手段。**如使用压缩纹理、使用MipMap、少做半透明等。
-
**不使用帧缓存和渲染纹理的时候,Clear。**原因看不懂,但是这个一般在Unity里是自动的。若涉及自己开发渲染管线,要记得这一点。
-
**不要频繁切换帧缓存的目标。**这在IMR里也一样吧?
-
**尽量在片元着色器中使用顶点着色器直接插值计算出来的uv采样。**好像只有自己写GLSL的时候需要注意这一点。
-
**走延迟渲染管线的话,Tile Buffer里的数据也可以利用,**不要浪费再渲染一遍G-Buffer。
-
**MSAA是更好的选择。**IMR中MSAA还是挺消耗性能的,但TBDR下MSAA非常快,但我不知道为什么。
-
**谨慎考虑数值精度。**移动端带宽吃紧,数据类型上能省则剩,能用fixd不用half,能用half不用float。
-
**别用曲面细分着色器。**涉及内存的读取,内存离芯片比On-Chip memory远,比较慢。
基本就讲了一下次世代的流程,一些工作流的常识,一些模型的规范。
收获不大,我曾在课程中亲历了次世代的流程,但是那次是极不规范的。
跟我记忆中的几乎没有差距。
本节很重要,也讲得很好。主要说了纹理压缩,是什么,为什么要做,怎么做的,如何应用到项目中。
texture compression。是一种能使纹理体积减小、分块保存的技术,目前有很多种,常见的有DXTC、ETC等等。
首先,直接把一张纹理塞给GPU、GPU是无法读取的。若不进行纹理压缩,届时CPU会介入,把纹理打成RGBA32(即有RGBA4个通道,每个通道8位,可表示0~255的数据。一个像素就需要32位也就是4字节的空间,1080P则需要近8M的空间,非常占用带宽。之前也说过在移动端对于带宽的要求十分严格,所以移动端一定要注意纹理压缩事宜)。若进行过纹理压缩,则渲染时不再使用原纹理,而是压缩后的纹理,经过压缩算法编码后的纹理数据块是可以被GPU直接读取的,新的纹理需要一定时间解压缩,但是由于其分块且解压缩成本不大,非常的划算。
有非常多种,下图中黄字标出的是目前常用的几种:
主要用于存多通道图。非常帅的压缩方法,后面极多压缩方法基本都基于此方法。首先把原纹理切成4X4的块,然后用一个64位的数据块保存这4X4的16个像素的信息。
64位数据中,其中32位用来存两个RGB565,另外32位用来存2*16的16个2位索引值。
两个颜色值是这16个像素的极端颜色值,而这16个索引是每一个像素的索引,标记这个像素的颜色是四个颜色中的哪一个。虽然数据块中只保存了两个颜色,但是可以在两个颜色间线性插值,以此得到中间的两个颜色。
上面的说法仅针对无阿尔法通道的纹理,若纹理有阿尔法通道,则会做一些小小的更改:
颜色D不再是插值出来的颜色,而是完全透明。相当于只用1位数据保存阿尔法通道。
这种算法的压缩率很高,能到6:1 。
在DXT1的基础上,扩展了一倍体积,多出来的64位,用来保存4位*16个的透明度信息。
在DXT1的基础上,扩展了阿尔法块,内含2个8位阿尔法极端值,和3位*16个的索引值(共64位),比DXT2/3可以保存精度更高的阿尔法信息。
通常用于保存单通道的纹理,方法同DXT4/5的阿尔法,精度上可能有提升。
用于两个通道的纹理,方法同ATI1,只是保存两个通道的。
广泛用于安卓平台的纹理压缩格式,底层思路仍于DXT1类似,只不过变成二级查找表,像素间的颜色差别仅通过亮度来区别。
简单说了一下什么是硬表面,什么不是。说了一下怎么做硬表面,核心还是次世代建模那一套,这次会对次世代补充一些东西。收获有限。
我从大二上高福星的课开始就不明白,到底什么是他妈的硬表面,为什么都在说。
硬表面可以说是一种按照“外观”、“感觉”来分类的模型种类,并没有极其严格的标准来说明什么是硬表面,什么不是。
我总结了了硬表面模型的一些关键词:倒角、厚重、结实、厚、金属、工业、光滑、平。
以下模型一般被认为是硬表面模型:
那什么是非硬表面?其实,不是硬表面、不就是非硬表面么……
我总结了一些关键词:褶皱、粗糙、易变形、不稳定、布料、皮革、锈迹。
以下模型一般被认为是非硬表面:
核心就一个:**倒角。**硬表面模型的拐角处几乎全是倒角,并且倒角的段数很高,又不会过于分散,可以参考一下桌子的边缘。做好这一点几乎就成了。
再往后,课程讲的就是次世代建模的部分了。要做好这个倒角,需要精湛的卡线技艺,卡线能使结构挺拔不弯曲,满足硬表面模型对“平”和“挺拔”的要求,同时又能得到漂亮的拐角。
我整理、试图理解了一下正确的次世代流程:
中模:有结构信息,有卡线。
高模:中膜平滑后得到。
低模:中膜删卡线后得到。
一般建模从中模开始建,然后先得到高模、最后用高模拓扑成低模低模,再把高模的法线烘培到低模的UV中、作为法线贴图保留。最终在游戏中使用低模+法线贴图体现高模的细节。
此节详细地讲述了Bloom效果如何实现。之前在入门精要我是了解过Bloom的算法的,在联想时也经常用这个Bloom。经过这节课学到了之前的一些遗漏点和理解错误的点,也更系统详细复合实际操作的流程。收获不错。
属于是有点理解过浅了。
泛光不仅是好看,在一些场合也是必不可少的存在。比如如果使用了HDR颜色,若不开Bloom,很难看到它的好的效果,只能看到HDR较亮的地方一片泛白,看不到颜色的”溢出、辐射“。同理的还有自发光贴图,若使用自发光,不开bloom也基本上看不到效果。
总体来说分4大步骤,也就是4个Pass
遍历原缓冲区,找出亮部,将暗部剔除 -》 对提取出的渲染纹理做水平模糊 -》 对提取出的渲染纹理做竖直模糊 -》 混合原缓冲区和模糊后的渲染纹理
下面细说这四个步骤
非常简单的一个东西,计算亮度是有公式的。
如此,这个Pass输出的渲染纹理就是:仅有亮度超过阈值的地方,颜色保持原亮度;而亮度在大于阈值的一定范围内时,逐渐变暗。小于阈值的地方一定是全黑的。
先一个Pass做水平、再一个Pass做竖直。本来一个高斯模糊是要计算25个像素的颜色的平均值的(假如高斯核5X5),这么做的话,其实只需要算10个像素的颜色平均值就行了。因为高斯核在X和Y都是对称的,所以可以这么来。
没什么好说的,在这个Pass的片元着色器中,用当前渲染片元的uv去采样原缓冲区(渲染纹理)和模糊后的渲染纹理,再直接把二者加起来,对,就是直接加,所以可能导致亮度大于一,这也正是人们想要的。
我原先的理解错了,这是两种不同的性能优化方式。这两种优化方式本质上是差不多的,都是降低要处理的信号的采样率,开得过大可能会导致模糊处出现虚影、或者不该亮的地方也亮了。以下是两种方法的详细过程:
降采样相关的参数是:down sample,是一个整数型变量,代表处理的信号、分别率降低多少倍。在bloom这个案例中,降采样使用在:定义提取出的亮部、和高斯处理的渲染纹理时,使其变为分辨率的几分之一,如下图代码:
这可以使模糊时,处理更少的像素,自然能加快它的速度。
我原来以为这菜是降采样,直到我这次注意到了一个叫做blur spread的参数,这是一个浮点型的参数。控制着:做高斯模糊时,采样滤波核的各像素的间隔是多大。这个间隔大的话,滤波核就不再是致密的,而是有间隔的。间隔较小的情况下只会损失一点效果,而却能节省好几次高斯的遍历。使用时的代码如下:
这里的Blur Size绑定的就是blur spread参数,可见其在竖直方向上,对本应偏移的量(一个纹素宽度)做了一个成倍的处理,使得滤波核产生间隔。
主要讲了PBR流程中、以及一些通用的流程中的模型规范。我只知道其中的一些,但是一直没有系统一点的总结,也没有合适的表述,这次正好总结一下。其实模型规范的大头要根据具体项目制定,这里就简单学一下思路,看看需要考虑哪些方面吧。
- 为了后续制作方便,如后续的绑骨蒙皮、绘制贴图等流程。
- 为了节省性能。
- 为了在外包、或者本社人员制作出不对的模型时、有依据和他们battle。
布线要求仅针对最终进引擎的模型,如PBR流程中,最终仅低模进入实际渲染流程,那么对中模和高模的布线要求则不会那么高。
要求有以下几点:
- 布线均匀。不能有的地方特别密有的地方特别稀疏(不是指必须完全均匀)。
- 布线密度适中。能够很好体现剪影,并且在关节处布线稍密集、而在平面处布线较稀疏。
- 避免出现多星点。我是第一次接触“多星点”这个概念,好像是模型师的黑话,意思是:连线超过4的点。这里不是完全杜绝,而是尽量减少,就算需要出现多星点,也不能把它放置在结构线上,需要把它挪动到相对平缓的地方。因为边缘上的多星点在对模型做平滑操作的时候,会出现不可预测的错误。
- 处理不在一个平面上的四边面。不同的DCC软件在处理曲面的时候,会用不同的方法做预连线,也就是随意选一组对角线连起来使四边的曲面变成两个三角面。这个“随机选择”是不可控的。如果不处理四边的曲面,则可能在不同的DCC中看到不同的效果,在同时之间传输文件时也容易出现偏差。要怎么处理呢?建模师提前处理不在一个平面的四边面就可以了,自己选一组符合自己要求的对角线连起来就行。
-
尽量打直UV,做到尽量横平竖直。一方面可以提高贴图空间利用率,一方面可以避免一些锯齿,据说斜的,45度的UV容易产生锯齿。
-
尽量均匀分配uv,杜绝uv非等比例拉伸。
-
硬边处UV必须断开。如果硬边处的UV不断开,会导致该处渲染时产生明显接缝。我也不知道具体原因。关于软硬边和平滑组,这课里学到不少,作为TA知识存到TA零散笔记。
我之前在202中了解过SSAO,面试中也被问过好几次,答了个基本思路,似乎是答对的。本节详细讲了SSAO的实现步骤,收获不错,修正了之前的一些误解。
和之前的3D空间下的计算区分开来,之前的叫“图像空间”(Image Space)。屏幕空间下的处理就基本是后处理了,输入是若干图,输出最终图。 关于AO、之前在零散知识积累中记过一些,但其实想来根本没有那么复杂。记得在入门精要中提到的标准光照模型中,有一项Ambient项,代表环境光,在那里这个项就是一个定值。但是为了模拟环境光遮蔽的效果,其实可以在Ambient项上做一个遮罩,使有的地方环境光亮、有的地方则暗,使得其立体感更强。 AO的原理就是对于每一个渲染点,我计算它在法线半球的可见性的Cos加权的平均,最终得到一个0~1的值代表环境光强度,把这个保存到贴图上即是AO贴图,和一个遮罩很像。 如何基于屏幕空间来做? 1.首先,根据屏幕空间的像素位置和深度(所以需要渲染深度图)可以构建一个三维坐标,作为这个渲染点的位置。 2.以这个渲染点为中心、记录的法线方向(所以还需要渲染法线方向图)为方向构建一个半球,半径自己指定。 3.向半球中随机撒点,通过点的z值和记录的深度图的z值可以判断这个点对于相机是否可见。简单判断是否可见往往会导致不该出现AO的地方也有AO,因为遮挡物可能离渲染点非常远。所以这里也可以加上一个判断,若二者深度相差太多则不算遮挡。 4.用Cos a(a为点到球心的连线与法线的夹角)加权平均洒下的各点的可见性,即可得到大概的环境光的强度值。 5.最终应该渲出一张灰度图,把它叠加到原渲染纹理中去即是最终结果。
这里指出几个错误:
- 说屏幕空间基本是后处理是不对的,屏幕空间的算法需要不少Buffer的支持,而后处理不需要,后处理只需要渲染完成的图像。
- 把AO的作用对象视为“环境光”也是不太准确的,按照我此时的理解,AO作用于“间接光照”的作用部分。
- 详细步骤中有大量错误,下面我会重新详细讲述SSAO的做法。
总的来看,可以粗略的分为以下几步:
根据深度纹理重构观察空间下的渲染点坐标 --》 根据法线纹理确定渲染点的观察空间正交基 --》 循环体,把定好的、标准空间内的一组随机方向移入渲染点的空间内,得到这组随机采样点的观察空间下的位置 --》 仍在循环体中,对比采样点的深度和采样点xy对应位置的深度纹理中的深度,若比深度纹理深,说明该处被遮挡,舍弃其贡献。否则计算其贡献 --》 遍历所有采样点后,得到该渲染点的AO值,使其影响原渲染结果的rgb亮度
接下来细说一些技术问题:
我原先以为,渲染点知道其自身处于的xy、z直接从深度纹理读出来就行。但其实不行,一方面深度纹理是编码过的,不能直接用,另一方面这三个值根本不在一个空间内,强硬的堆在一起实在没什么意义。
那应该如何重构?
基本步骤如下:
我要对一些步骤做出解释:
对于第1步:
-
这里计算的不是广义的屏幕坐标,广义的屏幕坐标是片元着色器中、通过i.vertex获取的那个坐标,这个坐标的值是很大的,是跟屏幕的分辨率相关的,坐标最大值可以是(1920,1080)这种程度的。
而讲师这里说的屏幕坐标其实是用于采样屏幕空间纹理的纹理坐标,因为其需要裁剪空间的输入,所以这一步放在顶点着色器算。既然是纹理坐标,那么这个值的每一维也都是0~1的。
对于后面几步:
那我就是真的看不懂了,呃呃。除了5,其他都在顶点着色器中算。
总之通过如上几步,最终在片元着色器中得到的向量view Pos就是渲染点在观察空间下重构出来的坐标。
TBN就是正交基。事先准备的采样点其实是相对采样点,它们是死的,不会变的。但是每个渲染点的法线方向不一样,如何让这些定死的采样点移动到渲染点的法线半球方向呢?
那就是使用正交基。入门精要简单提过正交基,正交基本质是矩阵,定义了一个空间下的坐标系。当这个坐标系下的坐标乘以这个TBN,就可以把这个坐标转移到父级的坐标系中。这里是类似于,给渲染点以法线方向重建了一个坐标系,提前准备的采样点乘以这个坐标系的TBN后,就转移到了父坐标系、也就是观察空间中。我们需要的就是观察空间的数据,所以必须要求到每一个渲染点的TBN。
具体如何构建?
首先需要获取观察空间下、渲染点的法线方向。这个方向可以通过对深度法线纹理采样、再进一步加工获得。
其次,生成正交基的做法很简单,就是把三个相互垂直的向量、也就是坐标轴磊再一起就是TBN了,所以需要求得切线和副切线。我们只知道法线方向,那么相应的切线其实有无数条的,所有这里先定死随便一个方向,然后让他投影到法线方向,再用这个随机方向减去这个投影方向,最后标准化,不就是一个切线方向了吗?底下那个图讲述的就是这个过程。知道了法线和切线,算副切线只要叉乘就可以了。
如此即可获得TBN。
上面已经拿到了TBN,随后对于每一个传入的相对采样方向,我们把它乘以TBN,即可得到在观察空间下的随机采样方向。我们把渲染点的观察空间下的位置、加上采样方向乘采样范围,不就是采样点在观察空间下的坐标吗,观察空间下的采样点坐标价值不是很大,因为它拿不到深度纹理中保存的深度。因此这里把这个观察空间下的采样点的坐标转移到屏幕纹理采样空间下,再用这个坐标对最开始的深度纹理采样,即可得到采样点处对应的真实深度。最后,我还需要采样点的深度值,这个值肯定是根据前面算好的观察空间下的采样点的坐标的z值进一步计算而来的,这里讲师没有讲。
最后,比较这两个深度,即可知道它是不是被遮挡了。若被遮挡直接取0,否则根据权值累加到循环体之外的变量中。循环结束,即可得到一个AO值。
都得到AO值了,那么直接用原本的颜色乘以AO值基本就可以了。
你知道,SSAO非常消耗性能,因其涉及大量的判断、循环,这些是GPU不擅长的,并且有大量的采样过程。因此有一些优化的手段,但是效果很有限:
-
构建正交基步骤中,使用随机的中间向量。之前为了好理解使用的是固定的,会导致各个渲染点的切线方向相对一致,随机性上表现稍差。让GPU自己随机是很脑瘫的做法,这里应该参照随机采样点的方法,实现把各随机可选项存到一个数组、或者图片里,到时候直接采样。
-
解决不该出现AO处也出现AO的问题。像这种地方(蓝色的是天空盒,极远),本不该出现AO,为什么还是有AO呢?想想一下,渲染天空盒的时候,如果离这个白的比较近,那么肯定有一些采样点会被判定为遮挡,自然会出现AO。为了解决这个问题,应该再做一步判断。在判断是否遮挡时,若确实被遮挡,则再看记录的深度和采样的深度之间的差距,若差距大于阈值,说明遮挡物离采样点特别远,这是不应该给AO,或者减小它的权值。这样性能开销会更大,但是效果会好一些。
-
根据遮挡物离采样点的深度差距来决定AO的贡献权值。众所周知,挨得比较近的地方AO大,那么采样的时候,肯定离得近的采样点的结果影响更大吧。以此作为权值的参考,会有更好的效果。
-
使用双边联合滤波降噪。SSAO的采样次数到64次时效果都一般,更别说更低的采样次数了。SSR也有类似的毛病。所以对于这种类似“噪声”的存在,使用滤波或许是一个好的选择(滤波本身消耗就不小,要仔细权衡)。
优点:
- 场景再复杂,也不影响SSAO的速度
- 不管是不是静态物体
缺点
- 性能不好,慢
- 质量比其他方式低
-
DCC烘培。直接烘培出一张纹理。
优点:
- 可以自由调节单一材质的AO强度
- 高质量
缺点:
- 模型必须展uv
- 工作量大,想要AO的物体,每一个都需要烘培,出来一堆贴图
- 一堆AO贴图,占用带宽
- 仅单个物体AO,物体之间的接缝处的AO出不来。
-
Unity自带烘培,连塞贴图的功夫都省了。
优点:
- 操作简单,一键傻瓜式
- 不用自己展uv
- 物体之间接缝的uv也能出来
- 快,比SSAO快你妈一万倍
缺点:
- Unity考虑性能,精度往往不高。
- 只有静态物体和动态批处理物体可以烘培。
- 烘培巨慢。
- 包体变大。
讲师极其不认真。讲的内容大部分是之前了解过的。但是之前一直有一些东西没有理解,希望借着这次机会彻底搞懂以下问题:
- base color贴图记录的到底是什么信息?具体说说这个信息是怎么用的。
- diffuse贴图记录的到底是什么信息?具体说说这个信息怎么用。
- specular贴图记录的到底是什么信息?具体说说。
目前主流的PBR工作流有金属粗糙度和镜面反射光泽度两种,对于AO、法线、自发光等常规贴图,它们的处理完全一致,这里不考虑。 金属粗糙度:baseColor贴图(RGB,其中包含了物质的基本颜色和金属的反射率值,反射率即是F0)、金属度贴图(灰度,指定金属度)、粗糙度贴图(灰度,指定粗糙度) 优劣: 非金属的F0固定为0.04,无法调整; 主流的工作流,用途广泛;
镜面反射光泽度:diffuse(RGB,Diffuse贴图严格影响着材质的基本颜色而对材质的其他特征(如反射率)没有影响。)、镜面反射贴图(RGB,记录金属和非金属的F0)、光泽度贴图(灰度,指定光泽度) 优劣: 可以对金属、非金属的F0自由调整,但是这也非常容易做出违反能量守恒定律的材质; 两张RGB贴图,对性能的要求会更高;
思考: 1.手连PBR是金属粗糙度工作流的,金属度参数用来决定镜面反射受到多少baseColor的影响。 2.对于镜面反射光泽度工作流,我猜测镜面反射贴图三维,分别记录两个F0、和类似金属度的值,用来在两个F0中插值。
之后的说明中:
- F0为什么叫F0?F0又代表什么?之前居然都没想过。F0其实是“0度反射率”,也就是入射光线和面法线平行时(直射时),表面有多少比例的光线镜面反射(剩下的透射,进入物体内部。注意是镜面反射,不包括漫反射部分)。F0是一个三维颜色值,分表代表RGB三种颜色的反射比例。金属的F0一般比较大,这也是用金属银做镜子的原因,即使入射光直射,也能有很好的镜面反射。而非金属的F0一般很小,低头看一下地面,比较难看到镜面反射。
Base Color贴图记录的是非金属的漫反射颜色和金属的F0。
Base Color贴图是一张RGB贴图,存了三个通道的值。Base Color的影响取决于物体的金属度。根据金属度贴图,如果物体是非金属,那么Base Color采样得到的结果就是作为**“漫反射”颜色使用,在PBR Shader中,通过乘以漫反射强度来使用。如果物体是完全的金属,那么Base Color的采样结果作为镜面反射的F0**使用,F0将参与镜面反射的FDG计算,从而影响最终渲染结果的颜色值。
上面这么说是方便理解和记忆,在实际的渲染中,Base Color就是一个输入,但在两处被使用,一处是计算漫反射时,影响最终的漫反射颜色;另一处是参与镜面反射的BRDF计算,通过影响菲涅尔项影响整个镜面反射的颜色。
那顶上那种说法是怎么来的?首先说它的第一处使用,金属是几乎没有漫反射的!所以这部分就直接被忽略了,所以说它记录的其实是非金属的漫反射颜色。置于它的第二处使用,F0在真正投入使用前其实会根据金属度插个值,如果是非金属,则F0就是0.04,不会变,如果金属度为1,则F0从Base Color取到。所以强调说Base Color记录的是金属的F0,因为它影响不到非金属。
- 不该包有光影信息(废话),但是可以包含微小AO信息。
- 暗色值不应低于50sRGB,颜色是三维值,这个规范的意思可能是每一维都不能低于50、也有可能是平均不能低于50、也有可能是只要一维高于50就行,我也不知道。
- 最亮不应高于240sRGB。
- 对于金属,Base Color纹素颜色值应在180~255sRGB之间。
Diffuse贴图保存的是漫反射颜色。
字面意思,就是漫反射颜色,它也是三个通道的贴图。对于非金属,材质的颜色很大一部分来自漫反射,所以这张贴图的效果会非常明显,而对于纯金属,它只有很小一部分颜色受到漫反射的影响,所以这张贴图的影响会非常小。所以,根据Base Color的逻辑,把Diffuse贴图的保存内容说成是:非金属的漫反射颜色、也不为过。
它的规范基本同上。
F0。
简单粗暴,我们知道,在metalrough工作流中,F0是用金属度作为参考值,在0.04^3和Base Color贴图中插值插出来的,而用Specular贴图就不用了,F0是三维值是吧,那就直接记下来三维值,不用再插值了,也不用什么metalic数据了。
- 如果要表现非金属,非金属的镜面反射是比较弱的,对应的就是F0三维值都比较小,对应到255的亮度、则应该在40~75sRGB。
- 如果要表现金属,金属的镜面反射很强,对应F0三维值大,在180~255sRGB之间。
- 其他的材质最好可以查表。F0是物理性质,是可以在真实世界测量出来的。这也就是specgloss工作流的缺点之一,F0可以随意修改,导致最后渲染结果可能打破真实物理规律。
呃……讲师讲得很垃圾。讲师直接用AI生成的声音,很生硬。内容大概就是阴影映射那一套,我们之前在202学过。在202的基础上,我学习了一些新内容,将在此做一些记录。
原理是先把相机移到光源的位置(补充:方向就是光源的方向。同时,并不是真的移动相机,应该是类似于新建一个相机的操作。渲染灯光坐标系下的深度图的许多参数和渲染Game窗口时不一样的),然后用一个标签为“ShadowCaster”的Pass,渲染出一张灯光坐标系下的深度图,判断一个点是否在阴影中时,只需要对比它在灯光坐标系下的深度和渲染出的深度图对应位置的深度即可。若比深度图的位置深,那说明这个点是被遮挡的,也就是在阴影之下的。否则说明其就是这个光源最近的点之一,可以被直接照射到。一般来说,生成投影这种事情是交给FallBack来做的,前面说FallBack不要乱写的原因就是这个,里面往往包含了阴影计算的内容。
这里的代码很多是被宏定义的。简单来说,想要一个物体可以被其他物体投影,则需要: 1.包含文件:#include "AutoLight.cginc" 2.在v2f结构体中加上:SHADOW_COORDS(2);大概内容就是声明了一组用于对阴影纹理采样的坐标。(注意,这个2不是随便来的,是根据目前的已经使用的纹理数量决定的。比如说我已经定义了TEXCOORD0和1,那么这个括号里才填2)(补充:这里其实就是在顶点着色器中,给顶点新加一套uv,它的坐标用于对Shadow map采样) 3.在顶点着色器中:TRANSFER_SHADOW(o);大概是计算纹理坐标。 4.最后,在frag中计算和应用阴影值:fixed shadow = SHADOW_ATTENUATION(i);最后在计算光照模型的时候,乘上阴影这个系数就可以了。 *:需要注意,使用宏的时候,变量的名称是卡的很死的,在阴影的计算中,顶点着色器只能叫vert,顶点的位置只能叫pos。
实时渲染的阴影隐射目前仍然没有一个最优解,无论是什么办法,消耗都不小,效果也都不太行。
这是Unity在用的阴影映射的方法。步骤如下:
绘制屏幕空间深度图 --> 从光源方向渲染灯光坐标系下深度图 --> 再次在屏幕空间做一次渲染,先根据屏幕空间的深度计算出灯光坐标系下的深度,再对比纹素的深度和灯光坐标系下深度图的对应位置的深度,把得到的“表示处于阴影中程度”的值渲染到一张渲染纹理中 --> 在渲染物体时,用屏幕空间的uv采样上一步生成的阴影图,即可得知渲染点“处于阴影中的程度”,把它用于计算即可
这个问题在202中提过:
百人计划中的意思好像大概也就是加一个bias容忍值,Unity的灯光组件可以调节这个参数。
锯齿一直是阴影渲染的大问题。202给出的方法是PCF。
上面提到传统阴影映射有无法容忍的锯齿重的问题,那么自然有人会去研发阴影的抗锯齿方法,PCF就是一种。请先回顾在就光栅化的时候的反走样方法,如MSAA,是不是可以用类似的方法,在渲染点对周围一个范围内采样、来得到不是非0即1的值呢?答案时肯定的,利用卷积,可以统计范围内的值,得到的0
1的中间值就可以视作阴影的强度,就可以得到不那么硬的阴影边缘了,也就达到了一定的抗锯齿的目的。注意,这里的卷积并不是像高斯模糊那种卷积,是这样:比如统计5X5范围内的覆盖情况,有10个被覆盖,15个未被覆盖,则认为是40%硬度的阴影。 详细来说,就是在正常ShadowMapping的过程中,判断渲染点在不在阴影下的时候,如果只对渲染出来的阴影深度纹理渲染一次,那么只能得到非0即1的值,表示是否在阴影下,但PCF可以多次对阴影深度纹理采样,综合多个非0即1的值,即可得到柔然的、01之间的值。
之所以阴影锯齿很重,最根本的原因还是阴影图分辨率有限。当物体离光源近还好说,但是物体一旦稍远,在灯光深度图中的采样次数就会很少,非常容易出现锯齿。这一点仅针对透视投影。
为了减轻透视导致的“远处采样率太低”的问题,Unity使用了“级联阴影隐射”。在Unity的项目设置的“质量”一栏中就可以调整。
讲师讲得不错。内容比较基础,就是一些抗锯齿逻辑层面的做法。像是做了一次复习,几乎没有收获。
1.涉及图像处理里学的东西。首先,走样的原因是采样的频率不够,跟不上图像的变化,采样得到的内容不足以很好表现原信号,就会出现走样的现象。信号是矢量,图像也可以理解为信号,比如x轴上像素的某一通道的变化。采样是光栅化的过程。 2.滤波就是把某一频段的信号删除、或者做特殊处理。如高通滤波、均值滤波等。 3.空间域下的卷积操作等于频率域下的点乘操作。比如对图像使用3X3的均值滤波、相当于把图像先傅里叶变换、再把变换后的图乘以3X3卷积核的图,得到的图再逆傅里叶变换即可得到空间域下相同的结果。嘶……具体怎么乘,不是很清楚,有时间需要搞明白。 4.最原始的三角形遍历模型中,每个像素只采样一次,算出来被覆盖则打上图元的颜色,否则不。这是非常硬的,也会产生很重的锯齿。可以尝试使用多次采样,也就是提高采样率,这样得到的结果就不再只是0和1,可以是一些浮点数,比如每个像素在内部不同的地方采样4次,看它们在三角形内外的分布情况,则可在边缘处得到不那么硬的值。这种做法叫做多重采样抗锯齿(MSAA)。 5.FXAA、快速近似抗锯齿,这是一种后处理抗锯齿方法,和一些传统的完全不一样。这种后处理是先拿到渲染好的、有锯齿的图像,再通过算法检测出锯齿严重的边缘,再用锯齿不严重的取而代之。效果好、效率高,缺点是效果不如MSAA好。 6.TAA、(时间抗锯齿),与MSAA和SSAA类似,都是一个像素多次采样,但它不是同一帧多次采样,而是每帧一次或数次,通过好几帧来完成所有一个像素中不同位置的采样点的采样,获取数据的时候,会获取前几帧保留的信息来计算采样的得值。
-
SSAA(super sample anti-aliasing、超采样抗锯齿)。渲染成倍于屏幕分辨率的图像,再在最后将图像缩小到屏幕分辨率(肯定不是单纯的缩小,而是把每一块的平均值作为缩小后纹素的颜色,类似MipMap)。这种方法效果肯定最好,但是非常消耗带宽和性能。
-
TAA(TemporalAA)上面说得太浅了,TAA不仅需要保存前几帧的结果,还需要计算motion vector,也就是运动方向,用于查找本帧目标渲染点在上一帧属于哪一个像素,这样才能拿到正确的参考。TAA的这一步加大了一些运算量,使用时还是需要权衡。和RTRT类似的,Temporal的方法有一些共有的毛病,比如需要预热时间、存在遮挡问题、存在阴影和倒影的延迟变化问题、存在相机倒退时的新区域无参考问题。
-
FXAA(Fast Approximate Anti-Aliasing、快速近似抗锯齿)。类似后处理的抗锯齿方法,先检测图像中类似于边缘的地方,再提取出来模糊、最后混合到原图像。和Bloom非常像不是吗。这种方法非常快。
-
常用AA速度
-
其他AA方法
疑似没活了,相同的内容这是第三次讲,又是PBR流程。讲师全程司马语气,不爱讲别讲,爬。完全没有收获。
是图形学底层的极其复杂的内容,我目前还在初步研究SRP,根本看不懂本课的内容。
我希望以后把SRP这块研究到一定深度,再来补充这一节的内容。
讲师的麦克风特别垃圾,我几乎一句都没听清。说的东西也很基础,而且他的理解有很大的问题,他这么讲课真的很不负责。几乎没有收获,在此借着这个机会我要说一下自己对UV的理解。
UV是顶点的一个属性,类型是float2,也就是一个二维坐标,对应平面上的一个点。
目前所有的Mesh模型本质都是一堆面片,我们渲染时需要把面片对应到贴图上,这样才方便在2D贴图上绘制信息。UV坐标记录的就是顶点在2D平面的位置信息。
UV之所以叫UV,是因为XYZ表示顶点属性中的位置,位置属性是每一个顶点都必须有的,而UV则不是。XYZ已被占用,所以顺延下来使用UV表示顶点的纹理坐标。
顶点可以拥有好几个UV坐标,每一个都对应一套UV。
有的DCC是默认顶点有UV属性的,有的则不是(比如Houdini),我认为
赋予顶点以UV属性、修改顶点UV属性的操作,就是UV展开。
UV展开几乎所有DCC软件都能做,各有各的好处。由于贴图在引擎中往往需要考虑压缩,所以UV坐标一般都被限制在0~1,超过的部分会根据纹理包装模式来判断。
UV展开的理想状态是,面全部展开后,没有重叠部分,且每一块没有拉伸、挤压,0~1的方形空间的利用率大,UV片之间有数个像素的空隙,防止由于精度限制导致的问题。
你知道UV是顶点的一个属性,那么其实,即使不把它作为纹理坐标隐射使用,单纯把它作为我需要的数据的容器使用,也是非常好用的。在米笔试的法线平滑工具的开发中,我就选择把法线数据写入UV。
说了景深是什么、景深在物理中是怎么形成的、景深在视觉表现上有什么作用、景深用代码实现的逻辑、简易景深的缺陷、后续的拓展思路。之前只是知道一点点景深效果,在项目中也稍微用过,但是没有具体而系统的了解。本节课收获较大。
我知道相机成像靠的是凸透镜组,它们是有一个焦点的,处于焦点处的的物体,无论反射出哪一个方向的光线,都会被精确地投射到成像面的一个点上。而不处于焦点的物体,它们反射出的光线多少都会被投射到一片或大或小的区域,这就导致它们反射的光线影响到了成像面上不属于它们的区域,表现在数学上,这就是高斯模糊。
现代摄像机有精确的透镜组、光圈和偏振膜的帮助,可以调节相机的景深。
- **凸显主体。**因为其他地方可以被景深可以的模糊掉,把焦点聚集在想要凸出的主体上。
- **营造虚幻、梦幻之感。**在一些城市的夜灯下、有前景遮挡的情况下,开启景深效果(类似大光圈)能产生漂亮的光斑。很有虚幻梦幻之感。
- **表现人类视线的转移。**影视中常用,这很符合人类的用眼习惯。人眼的景深很有限,看近还是看远,只能选一个。影视利用景深的变化,就能表示“现在的主人公,视线转移了”这样的意思。
一图流
就是一张8位灰度图,记录的信息是**“渲染点的清晰度”**。上面也说了,清晰不清晰,和渲染点离焦距的位置有很大的关系。
所以我们先需要获得线性的深度:
这里乘了一个叫做_ProjectingParams.z的参数,这个参数是相机的远裁剪平面。这么做了以后,将消除相机远裁剪平面对景深mask的影响。因为远裁剪平面会影响线性深度的值。
然后用深度对大概这样一个函数采样:
X是线性的深度,Y是清晰度,J代表的是焦距,对应最清晰的在哪里,F对应范围,看清晰度如何衰减。
这样计算即可得到一个代表“这个渲染点应该有多清晰”的值。整个画面都会计算一次,类似于生成了一张Mask。
在本案例中,就是做一遍高斯模糊,得到一张模糊后的图,存在缓冲区里。
其实就是用第一步得到的mask值,作为参考值在清晰图像和模糊图像之间插值。
做完以上几步,就可以得到一个还可以的景深效果。但是这不是基于物理原理得到的,是一个取类似的做法,它也存在很多缺陷。
缺陷:
- 关闭深度写入的物体,如特效、半透明物体,模糊的程度不可预测。毕竟是基于深度计算的,没有深度就没法正确计算。
- 颜色会泄露。还是简单后处理的问题,在模糊的时候,是均匀的模糊,这会导致远处的景色会拿到近处的景色的颜色,也就是颜色泄露。
- 无法模拟灯光在大光圈下的效果。这需要一些各项异性方面的支持,目前还不太了解。
因此,也有一些改善思路
- 高斯模糊时,根据深度调节滤波核大小。比如近处,使用较小滤波核,远处,使用较大滤波核。
- 使用联合滤波。在高斯模糊时,也可以拿到深度数据。再统计深度的影响,当其余采样点深度和中心点差异太大时,降低它的权值,这可以一定程度解决颜色泄露的问题。
讲师讲得散而凌乱。内容是我非常不熟悉的动作部分,这一块和建模一样,让我有点望而生畏……收获较小。
蒙皮是制作骨骼动画的关键步骤。简单来说就是设定骨骼如何驱动顶点、驱动哪些顶点。
以下是一些蒙皮方式的细则,我之前完全不知道有这个……
………………其他大部分讲的是偏艺术的非常零碎的内容,我认为暂时没有学习的必要。
主要讲了Shader中Blend命令的原理,顺带提了一下Cull和Clip命令的用法和原理。之前入门精要了解过,但是不深。这次相当于复习和加深理解了。
与PS的混合模式很像,你可以决定片元之间如何混合。若这个被渲染的物体是完全不透明的,则可以关闭混合。
最终显示到屏幕的,一个像素肯定只能有一个颜色。可是有时候,就是会出现,片元着色器的输出位置已经有颜色的情况,比如渲染半透明物体时。
所以混合的本质就是,我现在有两个颜色值,一个是本片元着色器输出的,另一个是颜色缓冲区在本位置的颜色,我如何综合考量他们二者,得到一个最终颜色,这就是混合的本质。
其实很好理解,看下图:
上图是原理层面,blend背后做了什么,下图是一个阿尔法混合的实例:
当我们使用了blend SrcAlpha OneMinusSrcAlpha时,系统会为我们做右上代码的事情。如上面所说,blend后面,第一个是源像素的混合因子,第二个是目标缓冲区的混合因子。这些混合因子为了普适性已经不再是数字和表达式,而是变成了文字,应该是某种引用。
对于因子的含义、以及混合计算操作符的定义,又多又复杂,一般来说也不太用得到,这里就先不记了。
以下是一些常用的混合语法:
非常常用的背面剔除,或者正面,或者不剔除。写在Pass中,和Blend属于并列关系。
可以填一个0~1的参数,当执行到这里的时候,会判断一下当前正在渲染的片元的阿尔法通道,如果比它的参数小,这个片元就会被舍弃。如果不填,这个参数默认是0.5。这和之前入门精要说的阿尔法测试是类似的。写在片元着色器中。
本节主要讲了使用Spine软件制作2D骨骼动画的方法和流程。作为TA应该不太会直接上手制作2D动画,应该只要了解和知道它的流程就行了吧?
-
PS切片准备
拿到原画后,需要把需要动的地方(如人体关节处、五官)、以及会出现遮挡变换的地方(比如头发,头发在运动过程很容易大幅度运动,此时若不切开,一块头发会像果冻一样被大幅拉伸)切开。
光切开不够,需要在拼接处绘制过度,如上图红框处。这样才能保证运动时不会出现断裂。
从PS导出时,需要添加脚本“LayersToPNG”,具体的作用我不是很清楚,这里讲师也没讲得很细……本来想自己探究一下,发现我的PS里并没有这个功能。我估计是Spine软件的PS插件。
-
导入Spine
从PS用Spine的插件导出后,应该有一个项目文件(夹),这个项目应该可以直接在Spine打开。
-
绘制Mesh
导入后在右侧视口应该能看见像PS一样的图层信息,点击图层会弹出一个网格小窗口,在这里可以绘制这个图层的Mesh。
绘制的方法就是沿着图层的边缘画一遍,我觉得这件事情非常机械,肯定有相应的自动小工具可以用。
基本绘制结束后,会得到一个全是三角面的Mesh(废话,Mesh都是三角面的)。这个Mesh内部也会不可避免地有一些点,如果你想做一些需要顶点动画之类的效果、对内部顶点的分布有要求的话,可以编辑Mesh,在Mesh内部加点、连线等。
至于为什么需要Mesh,我有一点猜测。在实时渲染中直接使用带透明通道的图片,是非常不划算的,一方面会有渲染队列、渲染顺序方面的错误,另一方面直接使用PNG可能会导致严重的Over Draw问题。现代的GPU非常适合用来渲染Mesh,所以用Mesh比直接用PNG应该更划算才对。
-
创建骨骼
2D角色骨骼创建不像3D的,有基本的模板可用。2D由于其风格(如几头身、默认姿势、视角等影响),搞一套模板可能是不太现实的。所以创建骨骼一般都从零开始。
是非常自由的步骤,想要动的地方加上骨骼就可以了。
-
绑定骨骼
创建伊始骨骼是和Mesh分离的,和3D骨骼动画一样,2D骨骼也需要绑定和刷权重。
在Spine的操作是:
选中Mesh --> 添加对其有影响的骨骼 --> 确认绑定 --> 调整各骨骼对顶点的影响,也就是刷权重
确认驱动方式是FK还是IK,也就是前向和反向动力学。这一点在Spine直接能做,像躯干这种一般用FK,肢体一般用IK。这一步主要是为了K帧方便,像肢体用IK的话更符合人类的逻辑,用起来更舒服自然。
-
K动画
没啥好说的,就是嗯K。
-
导出
这一步比较讲究,Spine不是仅针对Unity的工具,所以需要注意一些点。
需要导出:
- atlas文件。这个好像默认会导出,包含图集坐标数据。
- Json文件。包含关键帧动画信息。
- 图集。这是若干张图片。
去官网似乎可以搞到Spine在Unity的运行库,把这个运行库加入Unity项目中。
更改上面导出的atlas文件的后缀为txt,我也不太知道为什么……
把导出的所有文件拖入Unity项目。
此时运行库应该会根据这些文件产生一些Unity内可用的文件。
最后测试检查效果就行了吧。
空说流程还是挺难受的,权当了解一下美术的工作流程吧。
本节讲师详细地讲了骨骼动画的全流程,虽然之前做过一个,但是并不是很理解。本次算是复习,顺便了解一些细节,收获不错。
创建骨骼 --> 蒙皮 --> 调整权重 --> (解算IK) --> (绑定控制器) --> K动画 --> 导出到引擎测试
讲师讲了3种常用骨骼的创建方法:
-
Bone骨骼
这种骨骼的关键词是**“从零开始”**,就是自己从头开始指定,以前马同庆老师教的小鱼的骨骼创建,用的就是这种方法。这种方法几乎没有限制,可以任意调节任意一块骨骼的宽度、长度、侧鳍等诸多参数。理论上Bone骨骼可以做到另外两种完全相同的高度。
-
CS对象
也就是character studio功能集。它类似于从Bone骨骼抽象出来的一种工具,关键词是**“人形”**。人形的骨骼,用CS对象可以非常轻松地(甚至就是一键式地)创建。
-
CAT对象
character animation toolkit(角色动画工具箱)。比CS对象稍微底层的存在,可以更自由地指定四肢、触须等等奇异生物构造的骨骼,关键词是**“生物”**。同时工具箱内含有大量的骨骼预设,比如外星人、牛的基本骨骼。
骨骼本质上其实就是一堆简易多面体的树状层级。
前几节课简单了解了下蒙皮:
蒙皮是制作骨骼动画的关键步骤。简单来说就是设定骨骼如何驱动顶点、驱动哪些顶点。
这样的理解基本没错。
在max中,对一个骨骼物体附加Skin修改器,就可以开始给骨骼蒙皮。在蒙皮之前,骨骼对任何模型都没有驱动力。
首先会用“封套法”对于每一块骨骼确定该骨骼将要影响的顶点范围,随后才会再次逐骨骼块的修改各顶点的权重值。
这一步往往是很繁琐的。一个顶点是可以受到多个骨骼的影响的,那么这个顶点的位置受两个骨骼的影响的权重值是如何?这需要人为的指定。
在一些大幅度运动的关节处、如肘关节、膝关节处,权重不对的话会导致模型剧烈扭曲,面片相互穿插效果极差,所以应该先将骨骼调节至大幅弯曲的状态,再去对关节处两根骨骼块对各顶点的权重值进行修改,直到不出现剧烈扭曲、穿插为止。
这一步是可选的。人的四肢等类似的结构,使用IK指定Pos是一种更符合人类思考习惯的方式。其他的结构可能不那么合适,使用FK就好。
这一步也是可选的。我对控制器绑定的理解为:“将一部分骨骼的Transform数据绑定到一个虚拟物体上,通过操控虚拟物体来操控这一部分骨骼”,这样可以解决一些问题,比如:骨骼数量较多,难以准确选中,此时可以将虚拟物体放到较好点击的地方。再比如我要做一个毛笔尖的骨骼动画,毛笔尖较为柔然,需要数段骨骼,然而如果每次都按FK的思路一段一段去调,非常花时间。所以磨刀不误砍柴工,可以先把整个毛笔尖通过某种绑定(约束)绑到一个虚拟物体上,然后仅控制一个虚拟物体的上下、就能控制好整个毛笔尖的弯曲。
这里我想额外说一下眼球的绑定。眼球几乎是必然需要绑定控制器的物体,因为单独操作眼球很难做到对称不说,要选中和精确控制它也是十分困难的。这时候需要一种叫“注视约束”的操作,可以模拟人类的观察习惯,把眼球的运动绑到一个虚拟物体上。
嗯K,有控制器会好K一点。之前Houdini早期项目的足球那个教程,就教了一些绑定的简易知识,有需要可以回看一下。
主要讲了路径追踪那一套。在GAMES101中我全面了解了光线追踪和路径追踪,本节课毕复习了一些概念,纠正了一些误解,收获一般。
从摄像机到屏幕某个像素连线,得到的方向视作一条“感知光线”,让其投射到场景中,遇到表面根据表面的法线和材质进行反射、折射和衰减,经过数次弹射后,把每一次反射的点与光源连接,再检测其与光源的连线是否会被其他物体遮挡,若是表示其在阴影下,否则表示可以直接被光源照射到。把各个反射点得到的信息累加到这个像素中,即可得到最终的这个像素的颜色值。
在Whitted-Style的光线追踪中,物体只区分漫反射、镜面反射和透射。当光线打到漫反射表面。光线就不再继续反弹。这会导致无法体现间接光照,也无法体现Glossy材质(类似磨砂金属水壶的材质)的正确效果。为了解决Whitted-Style光线追踪的问题,提出了路径追踪,其本质是一种改良,核心思想和光线追踪是一样的,从观察点到像素连线作为“感知光线”,再根据反弹的结果决定最终的像素的颜色值。
只是摘了一小段。关于光追、路径追踪,在GAMES101笔记有详尽的记录。
-
Ray Casting、光线投射是什么?
光线投射是光线追踪的前身,它的思路是:从相机到像素,发射感知光线。对于击中的第一个物体(三角面),根据它的材质、法线和光照信息计算出应有的颜色值。不考虑光线的弹射。
-
Ray Marching、光线步进
之前做SSR的时候是自己实现过动态步进的,总之就是一种算法,能尽量快速地找到射线与物体的交点。以下是一些应用场景
简单讲了命名规范、DCC测试环境搭建、材质和模型规范。部分内容和59节讲的有重复。讲得较浅,收获较小。
-
全英文命名。
因为不知道哪一环就会不支持识别中文字符,然后出现深不可测的Bug。
-
储存位置规范。
资产存放大纲与目录
看这个,极其详细。
-
命名格式
对于可以自行命名的资产,为了查找时方便,需要有一套规范的命名标准。
课程中给出了一套供以参考:
总结一下,就是:(资产类型 )资产所属或资产父级(资产细则或资产附加信息)(资产类型细则)
比如此时我要保存一个Miku的手里的葱的颜色贴图,按照上面的规范就应该命名为:
T_Miku_Scalion_BaseColor
DCC的渲染环境和最后在引擎中呈现时肯定是不一样的,有以下因素都会导致渲染结果偏差。这些偏差可能会让美术不高兴。🤔🤔
-
光照
直接光照和间接光照,在引擎和DCC中都有很大区别,也难以统一。
-
曝光
应该是指相机。DCC的相机的参数和引擎的相机参数甚至底层算法,肯定都有不小的区别。
-
Shader
DCC和引擎使用完全不同的渲染管线,因此要统一Shader也是十分困难的。
-
后处理
基本同上,DCC几乎没有什么后处理,而引擎大量使用后期处理,会导致渲染结果出现很大偏差。
-
贴图的处理方式
DCC中一般以产品级呈现效果,而引擎考虑到性能限制和实时渲染需求,会对贴图做Mip、滤波、和纹理压缩处理,这会导致在细节上,DCC和引擎的渲染结果出现一些偏差。
综上,要搭建一个让美术高兴的创作条件是十分困难的,这是一个非常大的课题,以后有需求再研究吧。
-
使用图集
如果对包体和性能要求严格,则使用“共享材质”的思路,使用大图保存多张小图信息,然后通过UV区分采样。这样批处理会容易一些。
-
少用半透明材质
有很多可以替代半透明材质的方法。如果一个物体有半透明部分和不透明部分,一定要把这两部分分开,使用两个材质。
有兴趣可以研究一下 “阿尔法抖动” ,原神用这种方法模拟半透明。
-
半透明物体渲染顺序排序
如果物体涉及复杂的遮挡、缠绕,此时引擎无法很好地确定渲染顺序,需要手动指定。
先看下59节记的,这里做一点补充。
- 尽量只存在四边面。
- 四边面的四点尽量在同一平面,不要出现曲面。
- 根据项目要求控制面数。
看了一下后面。从本节开始,后面的内容变得不再基础(对于我来说),每个板块也不再是简单一节课就能说清楚,学习方式将出现一些改变。
本节课极长,主要的内容是比较顶层的工具使用方法、规范之类的,虽然之前对于动画、蒙皮、绑定这块已经讲了好几节课,但是这里又炒了一遍冷饭,同时深入了一点点。
-
关于“绑定”这个说法
有些美术把整个“创建骨骼、蒙皮、调整权重、解算IK、使用约束制作绑定”一整个流程都成为“绑定”。但是我认为绑定应该只包含使用约束制作控制器方便动画师制作动画这个步骤才叫绑定。
-
约束是组成控制器的单位,DCC中往往有很多种约束,基本是以某种可配置的规则把物体的Transform和另一个物体的什么属性联系起来。
-
骨骼本质是一套有严格父子层级的简易几何体,父物体Transform一般会带动子物体一起。但是如果子物体被其他约束控制,似乎就会摆脱父物体的控制。
并且约束似乎极其自由,在K动画的时候,约束的有无、配置也可以被打到关键帧里面。
Blende Shape是一种变形器。Mesh本质上是一群面片的集合,它的修改也基本都基于它面片的属性,如移动点线面的位置、倒角、挤出等等;在一些大开大合的运动关节处,使用骨骼使模型变形也是十分不错的选择,但是对于面部表情、模型细节形变等,不管是面片修改还是骨骼,都不能很好的、准确的使模型变形。DCC中也可以使用变形器修改物体的形状,变形器可以把Mesh抽象成橡皮泥一样的东西,然后艺术家通过类似雕刻的方式改变模型的形状,对于细节处的形变要求,使用变形器是更符合人类逻辑、也是更方便的选择。
变形器有很多种,目前能在游戏引擎中使用的只有Blende Shape。之前在联想实习的时候,接触过Blende Shape。
Blend Shape本质上保存的是局部区域的形变的相对最终结果,最终通过Lerp在Mesh原型和Blend Shape直接插值出理想的结果。
FBX文件可以保存多个Blend Shape,然后通过引擎或者DCC本身指定Lerp的参考值混合出想要的结果。比如制作了两个Blend Shape赋予模型,A取0.5,B取0.8,它们会混合出最终的结果。
和之前自学的PBR文章的重合度极高,收获较小,权当复习了。
关于PBR
GAMES202
-
什么是PBR?
以前的记录:
1.顾名思义,就是基于物理的渲染,其利用物理定律计算光照,相较于之前说的基于经验的光照模型能够得到更加准确的物理效果。 2.基于物理的光照模型必须满足以下三个条件: (1.基于微平面的表面模型。 (2.能量守恒。 (3.基于物理的BRDF。
然而,其实基于物理的渲染需要的条件是:
- 基于物理的材质(光照模型)
- 基于物理的光照(物理光源,有色温、亮度、有体积等参数)
- 基于物理的相机(普通的渲染相机,我也说不上它是基于什么的。但是基于物理的相机可以做到和真实相机几乎一样,可调节的参数也几乎一样,如曝光、光圈、快门等等)
以前记的也说不上错,但是要注意区分“基于物理的材质”和“基于物理的渲染”的区别。
-
关于能量守恒
以前的记录:
1.物理定律,能量既不会凭空产生,也不会凭空消失,它只会从一种形式转化为另一种形式,或者从一个物体转移到其它物体,而能量的总量保持不变。 2.表现在渲染上,其实很简单:出射光线的能量永远不能超过入射光线的能量。 3.看右边方程,这是渲染方程,Lo是出射光(观察方向)辐射度,Le是自发光在观察方向上的辐射度,后面是一个半球积分,对渲染点法线半球的所有入射光经过BRDF(材质)的作用后、反射到观察方向的结果积分,这二者加起来就是人能看到的辐射度。关于辐射度量学的这些名词,参考101的笔记。 4.在上面的微表面模型中就有体现,高光小且亮、大而暗,它们的总能量是一样的。 5.这个东西在渲染中怎么用呢?主要体现在计算反射类型的能聊比例上,首先由高光(镜面反射)部分的函数计算出高光所占的能量的百分比,用1减之即可得到漫反射能量的部分的占比。 6.渲染中的情况往往更加复杂,因为物体不只受光源的影响,其还受间接光的影响,即物体间的反射,也就是环境光,环境光加上直接光照就是全局光照,GI或者global Illumination。所以PBR往往需要计算四种光照,在镜面和漫反射层级下再细分直接光和间接光这四种。 *:在PBR中的体现:1.出射能量不能大于入射能量、2.kd + ks = 1
总感觉对于第四点理解有点偏差,这里重新讲述一下。
上图是经典的体现微表面模型和能量守恒的图,下面的数字代表粗糙度。
体现微表面模型:
粗糙度越大,kd越大,漫反射越强,镜面反射相应越弱;因为粗糙的表面反射的能量的方向更加平均。
体现能量守恒:
单看镜面反射,随着粗糙度增大,镜面反射的区域逐渐变大,但是镜面反射的亮度相应降低。
-
看到一个公式的中文化,感觉挺有意思的
内容是极其工业化的操作技巧,和一些相对落地的规范。基本都是动作TA需要掌握的知识,用在TA从模型手里接收模型后,把模型规范化、查找问题、命名等问题上。我有点不希望往这个方向发展,想仅作了解,本节收获较小。
拿到模型,第一手先检查模型本身,需要检查大概以下内容:
-
单位统一
Unity的默认单位是厘米,而DCC就不一定了。3Dmax的默认好像就是米。如果单位不统一,将导致模型直接拖入引擎后,大小不正确。
-
模型中线与Max视口中的中轴线对其
若不这么做,可能导致动画位置出现偏移。(我猜的
-
检查布线
动作TA还真是辛苦……之前的模型规范有提到过,意思就是,在大开大合运动的膝盖、手肘等关节,需要满足一个凸三凹二的需求,意思就是、关节中凸的那一边,布线需要较密,至少要3根线才行;对于凹的那一面,则至少需要两根。如果不,在骨骼驱动动画时,这些关节会出现剧烈的拉伸变形扭曲锯齿。
-
模型Transform旋转和位置归零,Scale保持111
-
检查零碎的点线面、隐藏和冻结的元素
Max这类DCC的树状层级往往做得很垃圾,东西一隐藏就看不见,要再揭开还挺麻烦。也容易产生看不见的点线面,这些不处理进引擎都可能导致渲染错误、或者出现不必要的性能开销。
-
检查法线方向、检查光滑组(软硬边)、检查需要合并的顶点
这块真的是知识盲区了,总结了一些课上讲的规范,很多我也不知道为什么……
-
设置CS对象为三角形颈部,取消三角形盆骨。据说对Unity适配好一些。
-
不让虚拟物体作根骨骼,Unity不认
-
IK类动画导出时需要勾选烘培动画。
-
塌陷骨骼动画后,隐藏虚拟体后导出。
我甚至不知道这一条在说什么……我目前的理解是:动画是像函数一样,记录了一堆线性的数值在文件中,播放的时候实时去根据时间去对函数采样,得到的值就是这个参数此时的值。而塌陷动画类似烘培,把每一帧的结果写入文件,使用时根据时间去读取文件,直接得到参数此时的值,这是一种空间换时间的做法。然而,似乎有的平台对未塌陷的动画的读取会出现深不可测的Bug,所以如果遇到深不可测的问题,可以尝试把动画塌陷后再导出,导出时勾选烘培动画。
- 顶点最多保存多少根骨骼的权重?Unity可选1、2、4和自动,这个值在DCC也需要设置,如果超过4在Unity会出错,所以需要统一这个值。