1.线性追踪
亮度值是一个空间函数,而光线追踪做的事情其实是求这个函数在视线线段上的线积分
结果为:光线在视线方向上作用值之和
视线上的所有采样点的亮度之和能用来表示光线在介质中散射的效果
2.光线的衰减
简单的公式:i = l/d^2 [采样点的亮度值 = 光强度/(采样点-光源点)^2]
3.等式
d^2 = dot(d,d);
4.散射
公式:HG公式。就是输入指定方向和光线入射方向夹角的cos值,求出指定方向散射光线的亮度。
我们要计算的是朝着眼睛方向的散射光线亮度。
g:介质散射性质(值越大散射越明显),cosThreata:输入指定方向和光线入射方向夹角的cos值
代码如下:
float cosTheta = dot(lightDr,-rd);
float result = 1/(4*3.14)* (1 - g^2)/ pow(1 + g^2 -2*g* cosTheta, 1.5);
5.透光比
透光现象就是说光在介质内内传播,会被吸收一部分,剩下的部分才能透过介质达到观察者眼中。
这里要用一个物理法则Beer–Lambert法则。这个法则描述的是入射光强度和透光强度的比值
公式可以简单的写成,Out = In*exp(-c*d)。
c是物质密度,d是距离。
透光强度随着介质的密度光传播的距离的增加成指数下降。
6.阴影
理论原理:连接采样点和光源点作一条线段,然后检测场景中这条线段有没有和别的可见物体相交。如果有交点就判定该采样点被阴影遮挡,不记入采样数据,反之正常计算
在shader中实现原理:实时渲染中的阴影是通过将像素点的世界坐标(在fragment shader中获得或由像素深度反推获得)乘灯光的viewProjectionMatrix获得该像素点在shadowmap下的uv,
并与shadowmap记录的像素点深度进行比较,若shadowmap记录的深度大于等于该点,则表示该点并没有在阴影下,应该受到光照,反之则表示该点受到遮挡,不应该受到光照。
7.体积光阴影
线段和几何形状的求交公式
5.体积光:光照亮度散射+透光比+阴影
光源的光照亮度L,采样点到眼睛的透光率T,光线在视线方向上的散射值P,阴影值V。
没有阴影的体积光就是雾
非均匀介质,比如有噪音的雾,还要计算采样点位置的介质密度D(一般不考虑这个情况,假设为均匀介质)
散射最终公式:散射S= L*T*V*P*D 【代码参考链接:https://www.shadertoy.com/view/XlBSRz】
体积光优化:
一、使用3d纹理保存光照和阴影信息
因为游戏渲染的时候同样需要计算阴影和光照,没必要为了渲染体积光重新计算一遍。论文[1]提出的算法是在游戏渲染的同时将光照和阴影保存在一个3d纹理中,之后计算体积光只要对3d纹理中的信息采样就行了。3d纹理的保存方式也有很多种,UE4使用了一种层级式样的3d纹理,因为同时保存了空间层级数据,在3d索引时更快。
二、使用随即采样减少采样次数
今年的独立游戏公司DeadPlay使用了随即采样的方法,很大程度上减少了光线追踪采样的次数,每个象素只采样了3次,使得高端的游戏特效在手机端也可以顺畅运行。
三、添加噪点和抗锯齿算法柔滑画面
随机采样可以结合TemporalAA算法平滑画面,每一帧的随机采样生成的随机场和TemporalAA每帧的ID关联,这样把采样分散到时间维度上,平滑后同样能达到较高的精度。
参考文献
[1]Volumetric Fog SIGGRAPH 2014 - Advances in Real-Time Rendering
[2]Fast, Flexible, Physically-Based Volumetric Light Scattering - NVIDIA Developer
[3]Physically-based & Unified Volumetric Rendering in Frostbite
[4]Low Complexity, High Fidelity - INSIDE Rendering - GDC
[5]Fogshop: Real-Time Design and Rendering of. Inhomogeneous, Single-Scattering Media.
6.体积光优化
降采样和高斯模糊(基于深度的正态模糊)。我们将目标贴图的分辨率设置为摄像机Render Target的分辨率的一半,也就是直接将计算量缩小到了之前的1/4,但是降采样后的图像马赛克化严重,我们可以使用高斯模糊,将其通过正态分布的模糊采样放回到原分辨率的贴图中,会给体积光带来一种朦胧感与意境
双向反射分布函数(Bidirectional Reflectance Distribution Function,BRDF)
用来定义给定入射方向上的辐射照度(irradiance)如何影响给定出射方向上的辐射率(radiance)。
更笼统地说,它描述了入射光线经过某个表面反射后如何在各个出射方向上分布——这可以是从理想镜面反射到漫反射、各向同性(isotropic)或者各向异性(anisotropic)的各种反射。
各向同性:果各个方向的测量结果是相同的,说明其物理性质与取向无关,就称为各向同性。
各向异性:如果物理性质和取向密切相关,不同取向的测量结果迥异,就称为各向异性
7.BSDF(双向反射分布函数) = BRDF(双向散射分布函数) + BTDF(双向透射分布函数)
一部分光线在介质交界处发生了反射, 并未进入另外一种介质,另外一部分光线则进入了另一种介质。
双向反射分布函数(BRDF)
反射部分的光照的辐射亮度(radiance)和入射光照的辐射照度(irradiance)的比例是一个和入射角度、出射角度相关的函数,
这个函数就被称之为BRDF。
双向透射分布函数(BTDF)
相应的,穿越介质的那部分光照的辐射亮度和辐射照度的比例就被称之为BTDF
这两部分出射光的辐射亮度总和和入射光的辐射照度的比例就被叫做双向散射分布函数(BSDF)
8.次表面散射效果
次表面散射效果
如果光线出射点的位置和入射点相距不足一个像素,我们就认为入射点和出射点位置相同,这时候当前像素的光照只受其自身影响;
如果入射点和出射点相距超过一个像素,则表示某个像素的光照结果不仅仅受当前像素影响,
同时还受附近其他像素的光照影响,这就是我们常说的次表面散射效果了
密度分布函数
次表面散射的光线密度分布函数(diffusion profile),可以理解为是权重查找表
是一个各向同性的函数
一个像素受周边像素的光照影响的比例只和两个像素间的距离有关。这个密度分布函数在有些地方称为diffusion profile,用R(r)来表示
如果该函数的绝大部分能量都集中在入射点附近(r=0),就表示附近像素对当前像素的光照贡献不明显,可以忽略,则在渲染时我们就用【漫反射代替】
如果该函数分布比较均匀,附近像素对当前像素的光照贡献明显,则需要【单独计算次表面散射】
次表面散射的计算可以分为两个部分:
(1)对每个像素进行一般的漫反射计算。
(2)根据diffusion profile和(1)中的漫反射结果,加权计算周围若干个像素对当前像素的次表面散射贡献。
可以简单地理解为diffusion profile就是一张权重查找表,不同的皮肤渲染方法,通常就是对diffusion profile的不同近似。
我们根据加权计算所在的空间,将皮肤的渲染方法分为图像空间的方法和屏幕空间的方法两类。
屏幕空间的计算复杂度和模型个数无关,随意采用屏幕空间的次表面散射
9.GPU Instancing
https://zhuanlan.zhihu.com/p/34499251
instance的意义在于,相同材质 相同shader 相同mesh 使用不同的属性 但仍然可以合批
GPU Instancing需要相同VBO,相同的着色器Pass, 并且绘制区别仅限于值类型参数的数值区别,GPU Instancing才会生效
当gameobject不连续时,渲染列队被打断,会导致分成多个批次。比如有多个相同的角色,每个角色都拿着相同的武器,由于武器是挂接在每个角色上的,会导致本应该相同批次的物体没有连续,无法在同一批次完成。
这种情况可以自己调DrawMeshInstanced,或者用srp自己控制列队
几条关键宏。
UNITY_VERTEX_INPUT_INSTANCE_ID
用于在Vertex Shader输入 / 输出结构中定义一个语义为SV_InstanceID的元素。
UNITY_INSTANCING_CBUFFER_START(name) / UNITY_INSTANCING_CBUFFER_END
每个Instance独有的属性必须定义在一个遵循特殊命名规则的Constant Buffer中。使用这对宏来定义这些Constant Buffer。“name”参数可以是任意字符串。
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
定义一个具有特定类型和名字的每个Instance独有的Shader属性。这个宏实际会定义一个Uniform数组。
UNITY_SETUP_INSTANCE_ID(v)
这个宏必须在Vertex Shader的最开始调用,如果你需要在Fragment Shader里访问Instanced属性,则需要在Fragment Shader的开始也用一下。这个宏的目的在于让Instance ID在Shader函数里也能够被访问到。
UNITY_TRANSFER_INSTANCE_ID(v, o)
在Vertex Shader中把Instance ID从输入结构拷贝至输出结构中。只有当你需要在Fragment Shader中访问每个Instance独有的属性时才需要写这个宏。
UNITY_ACCESS_INSTANCED_PROP(_Color)
访问每个Instance独有的属性。这个宏会使用Instance ID作为索引到Uniform数组中去取当前Instance对应的数据。(这个宏在上面的shader中没有出现,在下面我自定义的shader中有引用到)。
10.fillrate/OverDraw(压力主要来自透明物体)
alpha=0的情况下,不会产生颜色效果,但也会有Blend操作,会有消耗 什么
以下情况下需要关注:
在粒子特效,ui重叠多时
11.基于球面调和基的实时全局光照明
预计算相关的代码和工具可以参考这个git:https://github.com/pieroaccardi
1.球谐函数(Spherical Harmonics, SH)
https://zhuanlan.zhihu.com/p/34059900
用处:使用SH模拟动态全局光照
实时计算间接光照要计算最少一次积分,为了求解降低复杂度,需转换到另外一个空间里,利用新空间的某些特性,降低求解难度
函数空间:其中泛函分析是以函数空间为研究对象,利用某些已知函数空间的特性,去简化问题求解。其中SH为基的函数空间就是常用的工具之一
SH除了满足作为函数空间basis的基本条件外,还有以下特性:
正交性。
正交性保证了对于 任意两个定义在球面上的函数的卷积计算,可以转化为对应 SH系数的点积。
针对处处光滑连续的问题,SH basis的解快速收敛。这个性质说明,像间接光照这样的低频问题(高频的问题可以用小波求解),可以在SH空间用极少的basis项去快速得到近似解(3 bands, 9 coefficients)
旋转不变性
旋转不变性保证了在将环境光贴图投射到 SH 上之后,对于物体表面任意法线方向,我们可以对其进行旋转后采样
这个性质保证当环境光照发生相对旋转的时候,不会出现计算结果的闪烁
Lighting function 和 max(cos(theta), 0) transfer function的卷积(即我们要求解的环境光照的积分)正好可以压缩存贮在一个Matrix4x4里,对法线运算后重构环境光照
另外光滑连续函数在3D空间的卷积等于SH空间的点积 <- 可以用来计算更复杂的动态光照效果(Precomputed Radiance Transfer)
Unity中,其对天空盒的SH计算参考《Stupid Spherical Harmonics(SH) Tricks》里的算法
实现步骤
首先是Prefiltering,先对环境贴图的像素逐个对SH Basis做一次加权采样投影。
第二步是提取用于法线重构光照环境需要的矩阵信息。
《An Efficient Representation for Irradiance Environment Maps》里有完整的推导过程。这一步Unity的算法和Paper里给出的常数C1-C5差了一个PI,是在实际运算中抵消了。
https://blog.csdn.net/NotMz/article/details/78339913
球谐光照比较核心的几个点的理解
1.蒙特卡洛积分
将计算机尤其是GPU上非常难以计算的积分简化为了加法,这是球谐光照的前提
2。投影:
球谐光照的实质就是将复杂的光照信号投影到基函数上存储,然后在使用的时候再将基函数上的数据加起来重建光照信号
3.伴随勒让德多项式
想比如正弦信号,伴随勒让德多项式作为基函数不仅是正交的,而且是归一化的, 这意味着其具有旋转不变性,适用于动态物体
Unity通过烘培时的光线追踪计算出其光照原始信号,然后投影到基函数并存储其系数,我们在Shader中可通过 ShadeSH9 函数获取重建信号,ShadeSH9 实现在 UnityCG.cginc 文件中
在实际使用中,我们直接调用 ShadeSH9,配合LightProbe 即可读取到 precompute bake 生成的自发光信息
全局光照书中的定义
函数空间的投影和重建也是所谓球谐函数的基础,球谐函数本质上就是将傅里叶变换使用的单位圆上的正余弦函数扩展到单位球面上,这些基函数实际上就是将三维空间的勒让德多项式进过缩放是之恰好位于球面上,
由于单位球面坐标上的长度固定为1,因此球面坐标系退化为一个二维的单位球面坐标系,其两个坐标值构成一个空间的方向,因此球谐函数的线性组合可以用来表述一个与位置无关的方向函数,而方向函数在渲染中太普遍了,
例如环境贴图就是一个与位置无关的方向函数,表面的反射方程也是一个方向函数,它根据一个入射方向分布计算出一个出射方向分布,因此球谐函数可以用来表述光照传输函数和环境贴图光源,同样去掉高频的部分,
使用少量的系数就可以近似一个方向函数的低频部分,这就是预计算辐射度方法的数学基础,此外球谐函数的一些特性,如旋转不变性,卷积,内积等,这些也是辐射照度缓存算法的基础。
2.球谐函数应用
https://zhuanlan.zhihu.com/p/34059900
https://blog.csdn.net/NotMz/article/details/78339913
https://www.cnblogs.com/effulgent/archive/2008/04/15/1153799.html
https://huailiang.github.io/blog/2019/harmonics/
自定义天光:角色的光照。比如有些游戏里在夜晚的场景为了突显角色, 想让角色的受光强度和色调比场景要明亮强烈一些,即为自定义天光。
2种方案
1.一种方案是单独一个角色编辑场景烘培SH,然后直接从引擎中提取unity已经计算好的SH
优点:烘培速度快。
缺点:不直观,美术人员不能立即查看角色在关卡场景里的最终效果,需要反复在两个场景之间切换,调整参数。
烘培完成后应用时:使用Unity引擎烘培的天光参数,cginc文件SH开头那几个
怎么获取SH数据:unity如果想获取某个像素周围的间接光信息,直接通过ShadeSH9来获取。通过unity的c#接口LightProbes.GetInterpolatedProbe即可以拿到场景某处的这组9x3的L0-L2的基底系数,
这是一个结构体SphericalHarmonicsL2,访问它的3x9的数组可以把他封装成7个rgba的color
2.一种方案是在关卡场景里烘培和查看角色的天光效果,每次把调好的天光烘培完以后,提取给角色使用,然后再把关卡场景测试角色用的light probe信息revert。
优点:可以在关卡场景直接查看角色的天光效果色调强度是否合适
缺点:是unity 5.0以后的版本不能单独烘培light probe, 每次场景的光照烘培时间都很长, 调整反馈慢。
摒弃了 Unity 原本的烘培系统,通过只烘培 Light Probe 的形式自己读取数据建立全局光照,LightProbe里存储的是烘培后用球谐函数编码的全局光照
记录好SH后应用时:
从同样的Irradiance Map计算的结果,和Unity的计算结果是一样的,但是更快,方便在场景里预览
可随意指定的一张HDR Irradiance Map。角色的Glossy Reflection Map也可以单独指定,方便自定义一些金属质感的表现,一键烘培,不再需要引擎计算(?)
3.PRT(Precomputed Radiance Transfer)
https://blog.uwa4d.com/archives/Study_PRT.html
一种预计算的方法,将全局光照计算中的不变量预计算存储下来,实时渲染时只需要计算变化的部分
要实时地渲染出全局光照效果,其难点主要有三个:1)需要模拟复杂的BRDF;2)需要计算入射光线半球积分;3)需要计算遮挡,物体表面多次反射。
将这些复杂的光照计算过程看作一个光线传输函数(Transfer Function),将入射光信息看作函数的输入。并且利用球面调和基函数、光线传输的线性性以及预计算,将入射光线在物体之间多次反射传递的复杂计算变为简单快速的内积计算。
由于作者采用了低阶的球面调和基函数来表示,因此只考虑了低频的光照信息(环境光贴图的变化不大)
PRT 算法流程,公式看链接
Diffuse材质流程
1)先将环境光贴图投射到 SH 上,计算出一个 SH 系数向量。(环境光贴图投影到SH,得到一个系数)
2)利用离线的全局光照算法对物体进行全局光照模拟计算出传输函数,并且将传输函数也投射到 SH 上,得到一个系数向量。(全局光照模拟计算出传输函数也投影到SH,得到一个系数)
3)在实时计算的时候,将光照的 SH 系数向量与预先计算好的传输函数 SH 系数向量做点积,即可计算出物体表面上的光照。(2个系数点积作为物体表面上的光照)
由于 Diffuse 材质与视线方向无关,因此传输函数只需一个向量即可表示。
Glossy 材质流程
1)对于 Glossy 材质,不同视点观察物体表面同一点会有不同的光照。因此,Glossy 材质的传输函数需要增加一个视线方向的维度,变成一个矩阵。
2)实时计算时与 Diffuse 一样,将光照向量与传输函数矩阵做乘法,得到传输后的入射光照向量。
3)将该向量与物体材质 BRDF 做卷积(得到一个表示各个方向反射光线的向量)
4)最后,从这个向量中计算出视线方向的反射光线
在实时渲染时,采用如下步骤:
1) 计算物体 O 入射光 Lp;
2) 将 Lp 旋转到 O 法线方向的局部坐标;
3) 将 Lp 向量与 Mp 向量做点积,或者与Mp 矩阵乘法;
4) 对于 Glossy 物体,将传输后的入射光 L'p 与 BRDF 做卷积,并计算 R 方向反射光线。
当需要计算不同物体之间的多次反射光线时,采用如同单个物体一样的迭代计算,但在迭代时不仅仅计算来自自身的反射光线,也计算来自其他物体的反射光。
Q.如何在球上均匀采样
先产生一个正方形区域的均匀点,然后将其映射到球面上——这样就可以在球上均匀的采样。其实这个做法本质非常像UV纹理映射的关系——UV是正方形区域,球面是你要映射的纹理Mesh面
13。皮肤
https://zhuanlan.zhihu.com/p/43244741 曲率皮肤散射研究+matcap试验
https://zhuanlan.zhihu.com/p/43239846 对SSS Matcap贴图的研究
14.头发
https://zhuanlan.zhihu.com/p/43248692 头发效果研究笔记
15.体积光
https://blog.csdn.net/NotMz/article/details/77510932?utm_medium=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase&depth_1-utm_source=distribute.pc_relevant_right.none-task-blog-BlogCommendFromMachineLearnPai2-5.nonecase
16.屏幕空间环境光遮蔽(Screen-Space Ambient Occlusion, SSAO)
一种间接光照的模拟的近似实现方法。
SSAO背后的原理:对于铺屏四边形(Screen-filled Quad)上的每一个片段,都会根据周边深度值计算一个遮蔽因子(Occlusion Factor)。这个遮蔽因子之后会被用来减少或者抵消片段的环境光照分量。
遮蔽因子是通过采集片段周围球型核心(Kernel)的多个深度样本,并和当前片段深度值对比而得到的。高于片段深度值样本的个数就是我们想要的遮蔽因子。
17.使命召唤的光照方案
间接光用cubemamp做GI Specular(IBL),用SH probe做GI diffuse。
球谐预计算的本质是内积操作,类似对环境cubemap模糊的算法,而且球谐的阶数不能设太高,太高运算会成指数成长,性能就不太划算了,所以比较适合diffuse,
高光的计算,为了还原更高的细节,比如镜面反射周边的环境,这时候使用IBL更合适些
人物和道具:高中低采用完整pbr方案
直接光:GGXspecular + lambert diffuse
间接光: IBL Cubemap做GI specular + SH probe做GI diffuse
建筑:性能考虑,低配简化了一些光照
直接光:远景用shadowmask,直接光不进lightmap
间接光:IBL Cubemap + GPU Bake lightmap
18.
Unity中的预计算全局光照有两种
烘培光和预计算全局光,后者在Unity中被称作预计算实时全局光(Precompute Realtime GI)
Realtime Resolution 实时光照分辨率
值得注意的时,unity对于这个概念的说明其实很容易造成理解上的误区,使我们认为,这个值其实就是直接决定了最终生成的light map的分辨率。实际上,这个值仍只是一个系数,
它间接影响light map的分辨率。它将和后面提到的lightmap parameter参数中的Resolution相乘来得到最终的分辨率大小。最终的分辨率大小是基于每个物体的,并不是说我们设置了Realtime Resolution后,
整个场景的光照贴图就是统一按这个分辨率生成了。
Q:那么Realtime Resolution有什么用呢,为什么不直接使用lightmap parameter参数中的Resolution呢?
A:这是因为,如果没有这样一个参数的化,就需要手动的为每一个需要烘焙进light map的物体设置lightmap Parameter,通过其中的lightmap Resolution来指定分辨率。当场景中我们有大量的物体时,
这个工作就变的不是很有效率了。所以通过Realtime Resolution可以对场景的大部分物体指定一个默认的分辨率,来简化这一过程
Vexel 体素
是数字数据于三维空间分割上的最小单位,体素用于三维成像、科学数据与医学影像等领域。
可以认为是3D空间的像素。我们知道像素在2D中是正方形的,那么相应的体素就是正方体了。那么一个3D空间的模型体素话后,就是有许多的正方体构成的(想象一下MineCraft)
Cluster 簇
簇简单的理解就是场景的体素化代理。在这里,我想解释的是代理(proxy)这个过程,理解了它,也就能很好的理解簇了。代理,在这里是我们使用体素来表示静态场景几何模型的表面,并将这些体素用于光照计算的这样一个过程。我们将复杂的几何表面,通过体素化,
简化为一个个由立方体所代表的表面。然后由这些立方体的某一个表面组成我们要进行光照计算的几何表面。这时,这些体素就被称为簇(cluster)
UV Shell
UV Shell是拓展模型UV时,一块模型拓展后的区域就是shell,一个模型可能会被拓展成一个shell,或是多个,这取决于拓展的方式方法和技术。
我们知道一个模型可能有很多的面(这里不是值顶点构成的三角形面,而是从更直观的认知上看到的面)。比如一个正方体,就有六个面。展uv时,我们可以将这6个面展成一个(cubemap)区域,也可以展成6个区域。
那么这个区域就是shell。如果对于更复杂的模型,同样的,也许我们有办法将整个模型的面展成一个区域,也可能因为面的复杂度,我们要展成多个区域。无论如何,知道区域就是shell就可以了
UV Chart
和UV Shell相关的概念,就是uv chart。这个概念应该是unity中提出的。首先我们需要记住,chart是一个正方体的小块。我们展好的shell,它的轮廓则是任意的,我们用N个chart来覆盖这个轮廓的区域,那么最终形成的一块边全是由正方形组成的区块,就是uv chart
19.IBL和SH的关系
IBL 采用了真实拍摄的环境光贴图作为入射光,因此能够更加逼真地模拟物体在真实环境中被照亮的情况。
但是这一算法需要对立方体环境贴图进行采样,计算来自环境贴图各个方向的入射光对物体的光照信息,这一过程时间开销非常大
所以通过将 入射光和材质在半球面上的卷积计算 转换 为球面调和函数基(SH)上的点积,减少实时计算的开销
20.蒙特卡罗法(Monte Carlo)
21.探究光线追踪技术及UE4的实现
https://www.cnblogs.com/timlly/p/11366199.html
22.
背光:光源从主体背后的情况下的效果,一般会导致场景过曝或人物过曝,需要通过补光进行调整,可表现黄昏剪影
色差:表现为高光区与低光区交界上呈现出带有颜色的“边缘”
23.BumpMap和NormalMap
https://worldcter.com/2022.html
BumpMap一种是Emboss Bump Map(浮雕凹凸贴图),它使用的是Height map,原理是在原始图像的基础上,对高度场图像进行复制、轻微平移、差操作。但它存在很多严重的局限性,它只能用于漫反射表面,对于镜面高光来说是不可能的。当光源直接照射在物体表面时,如果没有偏移,那么物体表面就不会出现任何凹凸现象。
Normal Map,这是目前图形硬件中使用的主要方法,它不需要存储高度,只需要将表面的实际法线作为(x,y,z)向量存储在法线图中,然后可以将含有法线的凹凸纹理和经过插值的光源向量在每个象素点结合起来,可以使用点乘。它的一个优点就是可以直接用来计算凹凸块上的镜面高光。
BumpMap在渲染时没有倒角高光,而切线空间下的NormalMap有倒角高光,具体看参看以上链接
24
重要性采样( Importance Sample):蒙特卡洛积分的一种采样策略。思路是基于分布函数,尽量对被积函数分布可能性较高的区域进行采样。
多重要性采样(Muti Importance Sampling, MIS) :估算某一积分时,基于多个分布函数获取采样,并期望至少某一分布与被积函数形状适配。即根据各种技术对采样进行加权计算,进而消除源自被积函数值与采样密度不匹配造成的较大反差。
大数定律(Law of Large Numbers) :在试验不变的条件下,重复试验多次,随机事件的频率近似于它的概率。即偶然中包含着某种必然。
蒙特卡洛方法(Monte Carlo Methods) :一种以概率统计理论为指导的数值计算方法。是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。
低偏差序列(Low-discrepancy sequence) :一种确定生成的超均匀分布列,也称为拟随机列、次随机列,常见低偏差序列有Hammersley,Halton等。
拟蒙特卡罗方法(Quasi-Monte Carlo Method) :使用低差异列来进行数值积分和研究其它一些数值问题的方法。
25.Cook-Torrance BRDF高光部分分解
Microfacet Cook-Torrance BRDF是实践中使用最广泛的模型,实际上也是人们可以想到的最简单的微平面模型。它仅对几何光学系统中的单层微表面上的单个散射进行建模,没有考虑多次散射,分层材质,以及衍射。Microfacet模型
D(h) : 法线分布函数 (Normal Distribution Function),描述微面元法线分布的概率,即正确朝向的法线的浓度。即具有正确朝向,能够将来自l的光反射到v的表面点的相对于表面面积的浓度。
F(l,h) : 菲涅尔方程(Fresnel Equation),描述不同的表面角下表面所反射的光线所占的比率。
G(l,v,h) : 几何函数(Geometry Function),描述微平面自成阴影的属性,即m = h的未被遮蔽的表面点的百分比。
分母 4(n·l)(n·v):校正因子(correctionfactor),作为微观几何的局部空间和整个宏观表面的局部空间之间变换的微平面量的校正。分母需要避免为0,一般会添加非常小的正值
26.
HDR(High Dynamic Range),高动态范围。High值得是亮度的范围更高。正常屏幕上一个像素是由RGB三原色组成的,每个通道用八位二进制表示,也就是0-255,而真实世界的亮度的最大值要远远超过屏幕上能够显示的最大亮度值,比如太阳的亮度会是屏幕亮度的几万倍,这个就是所谓的High。
HDR可以模拟高范围的亮度分布。实现这样功能的技术叫做ToneMapping,翻译为色调映射技术。这种技术会让画面对比度更加柔和,将高的亮度范围更加平滑地缩放到0-255这一低光照范围,主要运用的原理是局部适应性。人眼在比较暗的地方,也能看清东西,但是突然到了一个比较亮的地方,就会感觉模糊,需要一会儿才能适应当前的亮度水平
27.
RTT:
MRT:
28.
Graphics.Blit(src, target, mat),这个函数的本质是,绘制一个四方块,然后用mat这个材质,用src做maintex,然后先clear为black,然后渲染到target上。这个是一个快速的用于图像处理的方式
29.
Z-Pre Pass剔除像素(即HSR):只写深度不写颜色
31.
透明度交叉渲染(OIT)
透明排序问题,常用方法(最好从设计上规避透明穿插):
避免排序:
用alpha test、alpha to coverage代替alpha blend,虽然半透效果不如blend,但是不会不会碰到穿插问题,而且效率也更高
考虑排序:
深度缓存
油画家算法
思路:将场景中的多边形根据深度进行排序,然后按照顺序进行描绘
缺点:消耗大,不实用
depth peeling(深度剥离,得在相机上处理,非常慢)
渲染正常视图,将这一层深度剥离,渲染下一层深度的视图,以此类推。渲染每一个深度的图像,然后把所有的深度渲染结果混合起来,多pass算法,具体的pass数和场景最大的深度复杂度有关
深度剥离是一种对深度值进行排序的技术。它的原理比较直观,标准的深度检测使场景中的Z值最小的点输出到屏幕上,就是离我们最近的顶点。但还有离我们第二近的顶点,第三近的顶点存在。要想显示它们,可以用多遍渲染的方法。第一遍渲染时,按照正常方式处理,这样就得到了离我们最近的表面中的每个顶点的z值。在第二遍渲染时,把现在每个顶点的深度值和刚才的那个深度值进行比较,凡是小于等于第一遍得到的z值,把它们剥离,后面的过程依次类推即可
缺点:需要对透明物体进行N遍的渲染
https://github.com/jackie2009/depthPeeling
https://github.com/candycat1992/OIT_Lab
https://zhuanlan.zhihu.com/p/92337395
Stencil routed(D3D)
Per-pixel linked lists(原子计数)
这种方法利用SM5.0(这算是一个限制吧)的structured buffers和atomic operations[4]来建立每个像素的链表,然后对链表进行深度排序,最后按照排序结果使用Ray Marching方法来进行渲染。
理论性能比Depth peeling高一些,因为后者要N个pass所有pass都要处理所有的fragment,而这个算法只要2个pass
一个pass是无序存节点到公共空间,另一个pass是每个像素都执行一个frag shader来从公共空间取当前pixel的链表,然后排序
缺点:但是,Fragment and Link Buffer的大小无法事先比较精确的控制,这可能会导致空间浪费或者溢出。
优点:这种方法产生的数据(这里的链表)涵盖整个场景的信息,可以使用这些数据来做很多事,比如:体素化甚至光线跟踪
Adaptive transparency
Weighted blended OIT(加权平均值:得在相机上处理)
使用简单的透明混合公式来实现无序透明渲染的算法,它通过扩展透明混合公式,来实现无序透明物件的渲染,从而得到一定程度上逼真的结果
此算法的主要思想如下:
对于某个位置的像素点,如果所有的不透明物件是相同的颜色,那么渲染的结果与它们的渲染顺序无关。那么,对于不相同颜色值的情况,如果我们用某一个颜色来替换这些颜色,比如这些颜色的平均值。对于这种情况,我们使用各个颜色的不透明度作为权重来计算出它们的平均值。
优点:效率高,速度快,只需要对物体进行一次的渲染,然后加上一次全屏的后处理。缺点:结果只是一个近似值,而不是确切的正确结果。
结论:效果仍然远远好过不做任何处理的简单透明混合
https://github.com/candycat1992/OIT_Lab
Pixel sync
https://github.com/candycat1992/OIT_Lab
https://blog.csdn.net/poem_qianmo/article/details/72857602
https://zhuanlan.zhihu.com/p/92337395 次序无关的半透明渲染实现
32.unity层级相关
透明物体排序的第一权重是renderQueue,第二权重是sortingOrder,最后是深度
33.
光线投射 ,光线追踪与路径追踪
34
CascadeShadowMap(层级阴影)
35
Procedural Sky,瑞丽散射,米氏散射
36.
蒙皮矩阵:能把网格顶点从原来位置(绑定姿势)变换至骨骼的当前姿势的矩阵称为蒙皮矩阵。蒙皮矩阵把顶点变形至新位置,顶点在变换前后都在模型变换空间中
37.
VBO:就是用来管理存储在GPU的显存上的顶点内存
EBO:被设计用来存储顶点地顺序也就是索引,根本目的是解决数据冗余地问题
VAO:顶点数据存储在VBO里面了,但是每次切换顶点缓冲对象都要重新配置其属性,这样很不方便,VAO可以解决这个问题,它记录了VBO及其属性配置。这样我们绘制一个物体时,只需要绑定相应的VAO就行了
glBeginTransform Feedback:就是将大批的数据传递给 Vertex Shader,将 GPU 计算过后的结果通过一个 Buffer Object 返回到 CPU 中,CPU 再从 Buffer Object 读取数据(或直接将 Buffer Object 传递给下一步),在随后步骤中使用
38.
adb shell cat /proc/meminfo查看RAM使用情况
VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
39.
软阴影:软阴影的意思,是阴影的亮度,是可调的,阴影是可以做各种优化的,例如边缘是可以虚化的,做抗锯齿的,阴影是渐变的
40.
显存频率:一次传输的频率
显存位宽:一次传输的量
显存带宽:显存带宽 = 显存频率 * 显存位宽 / 8
杂
clip发生在融合blend之前,blend发生在所有颜色输出之后的帧缓存
批处理可以合并不同的mesh,而GPU Instancing主要是针对同一个mesh
GPU Instancing是不支持SkinnedMeshRender的,也就是正常情况下我们带动画的角色是无法使用GPU Instancing来减少Draw Call的,实现了GPUSkin的角色才可以用
Bindpose 的作用是将模型空间中的顶点坐标变换到骨骼空间中(是骨骼矩阵的逆矩阵)
AnimationClip的BlobSize是从文件反序列化出来的对象的二进制大小
ALU:算术逻辑单元
填充率(Fill Rate):填充率指GPU每秒能够渲染的屏幕像素数量
VRAM usage 显存的使用情况,VRAM总大小取决于你的显卡的显存
VBO Total 渲染过程中上载到图形卡的网格的数量,这里注意一点就是缩放的物体可能需要额外的开销。
GFX:内存峰值
-------------------
TODO
间接光照和积分的联系
全局光照的概念和组成
光线追踪 Ray Tracing
路径追踪 Path Tracing
光线追踪、路径追踪、光线投射的区别
环境光遮蔽 Ambient Occlusion
马尔科夫链模型
光子贴图
基于图像的光照IBL
环境光遮蔽
数学
基函数
径向基函数
函数空间与傅丽叶变换