Unity SRP自定义渲染管线 -- 5.Directional Shadows

原文:https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/directional-shadows/

  • 支持多个方向光阴影
  • 控制阴影距离
  • 定义独立的主光源
  • 渲染和采样级联阴影(cascaded shadow map)
  • 使用球形剔除

1. Shadows for Directional Lights

直射光和聚光源在概念上没有什么本质不同。除了直射光来自无限远的地方,两者基本相同。所以只需要一些调整,就可以让聚光源阴影的方法适用于直射光。我们将进一步改进我们的渲染管线,让它能混合直射光和聚光源的阴影。

1.1 Configuring Shadows

目前ConfigureLights中只处理了聚光源的阴影数据。而处理直射光源阴影的代码和聚光源的是相同的。为了重复利用这些代码,我们对代码进行一些重构,把它们写成单独的方法。

与聚光灯相比,渲染方向光阴影贴图时有些不同,因此需要在处理时指明它是直射光。我们用阴影数据的z分量来作为判断的标识

1.2 Rendering Shadows

对于方向光,我们需要用ComputeDirectionalShadowMatricesAndCullingPrimitives函数来获得裁剪信息,然而聚光源是用ComputeSpotShadowMatricesAndCullingPrimitives函数。重构部分代码,声明一个bool变量,用该变量保存是否有有效的方向光或者聚光源。

如果阴影数据表明我们处理的是方向光,就调用ComputeDirectionalShadowMatricesAndCullingPrimitives 。这个方法有更多的参数,因为它支持阴影级联(这里我们先不用)。第一个参数要求提供一个光源序列,接着是级联的序列以及级联的数量。我们现在用不到级联,所以序列设为0,数量设为1。之后是定义了级联分级的三维向量,我们使用(1,0,0)。然后是整型的图块尺寸和阴影近平面值。最后是投影矩阵等输出参数。 

splitData数据中包含了一个有效的剔除球体。该球体包裹了所有需要被渲染进直射光阴影贴图的物体。这对于直射光来说非常重要,因为直射光不像聚光源,他会影响所有物体,我们需要有一个剔除球体来限制渲染进阴影贴图的图形数量。对于聚广源该设置没有效果,没有什么影响。

1.3 Shadow Distance

此时我们应该可以得到方向光的阴影贴图了。但是看起来我们得到的贴图是空的,即使有也可能只是几个小点。造成这个现象的原因是这个贴图需要涵盖的范围太广了,覆盖了摄像机能够看到的所有东西,默认是1000单位,由相机的远平面控制。想看到贴图的内容就要大幅降低相机远平面距离。

但阴影的渲染范围并不应该取决于相机远平面,这只是默认的情况。阴影距离也能控制阴影的渲染范围。阴影距离通常远小于相机的远平面。两者综合考虑既可以限制阴影渲染的范围,又可以处理比阴影距离更小范围的情况。

在MyPipeline中为阴影距离添加一个字段,并在构造方法中设置。我们从相机中提取阴影距离并赋值给剔除参数。因为渲染相机可见范围外的阴影没有意义,所以使用阴影距离和相机远平面中的最小值更合理。

在MyPipelineAsset中为阴影距离添加一个配置选项,并设置一个合理的默认值,比如100。

1.4 Investigating Shadows

阴影距离降低到合理的值,直射光的阴影终于出现了。我们将光源的阴影偏移设为0并使用一个更大的平面作为地面。使用单个直射光照射。

因为偏移设为了0,我们可以大致看到阴影贴图覆盖的区域。和聚光源的阴影不同,方向光的阴影贴图随相机移动而改变。另外,阴影贴图的边缘也会影响超出阴影范围的场景物体,这是因为我们采样坐标会超出贴图边缘(结果会采样边缘的值,因为我们纹理设置的是clamp),这导致贴图的边缘被拉伸至无穷远。当我们的阴影光源多于一个时,拉伸消失了,因为我们为每个图块使用scissoring清理了边缘。

然而当采样多个超出范围的tiles时我们会得到错误的结果,tiles越多,结果越糟糕。 

1.5 Clamping to Shadow Tile

方向光阴影贴图有些麻烦是因为当它们被采样时,无论物体是否在阴影贴图的覆盖范围内都会进行采样。解决方法就是限制阴影采样坐标在tile内。我们在缩放到正确的图块前将阴影空间位置限制在0-1之间。之前没有做限制我们可以在MyPipeline里完成整个转换矩阵的计算,现在我们不得不把这一步移到shader里了。

tile scale信息对于变换时是必须的,我们将其传入shader。声明一个全局的vector用于保存阴影信息,将其命名为_GlobalShadowData 并持有它的标识符。

offset信息也是必需的,我们将其存储在ZW分量中。

之后移除对图块矩阵的乘法计算并在shader中在阴影缓存区添加一个全局阴影向量

在ShadowAttenuation函数中,在透视除法后对阴影位置的xy坐标做限制,将其限制在0-1范围内,之后再应用图块的坐标变换。 

直射光阴影需要透视除法吗?

不需要,因为直射光阴影贴图用的是正交投影。阴影位置的w向量恒为1,但是我们要混合直射光和聚光源,所以我们统一执行透视除法。

1.6 Always Use Scissors

我们解决了在多个图块时的阴影杂乱( shadow soup)问题,但是当场景中仅有一个方向光时阴影贴图的边缘仍会被拉伸。我们在RenderShadows中设置成无论几个光源都使用裁剪来解决这个问题。

1.7 Clipping Shadows Based on Distance

尽管阴影的距离是根据相机视角的距离,但是阴影并不是在当物体离开这个范围后立刻消失。这是因为阴影贴图覆盖了一个立方体的空间区域,只要这个区域的一部分在范围内,就会整个都渲染。方向光随着相机的移动阴影贴图也会重新渲染,所以对于这一问题方向光很合适,但是聚光源就不一样了,它的阴影空间区域和光源锁定,即使阴影距离只占空间的很小一部分,最终渲染的还是整个区域。结果就是聚光灯阴影贴图包含的所有阴影同时出现和消失。

我们可以使用配置的阴影距离来剪切阴影使阴影消失的边界线更统一。要想这么做,就得把阴影距离传给shader。我们将它放在全局阴影数据向量的第二个分量中。在我们实际裁剪时,我们用的是它的平方来进行比较,所以我们就直接存储阴影距离的平方。

在shader中,我们还需知道相机的位置。Unity在配置相机的时候就会自动提供这个信息。所以我们要做的只是在UnityPerCamera 缓存区中添加一个_WorldSpaceCameraPos 变量。

创建一个DistanceToCameraSqr函数,该函数输入世界位置,输出与相机的平方距离。

ShadowAttenuation中调用这个方法,检查是否超出了阴影距离,如果是就跳过阴影采样。

现在所有的阴影都在相同的距离消失,而不会突然的出现和消失了。

我们可以平滑的过渡阴影吗?

你可以添加一个渐变距离并使用一些过渡函数来实现,如线性插值,smoothstep等。

2. Cascaded Shadow Map

阴影贴图的缺点就是作为纹理,其分辨率必然是有限的。虽然你可以提高纹理分辨率来获得更好的效果,但仍没有摆脱这个限制。聚光源只覆盖了一小块区域,所以它的效果可以接受。但对于方向光,它的照射范围是无限大的。在视野远处的阴影效果也许还可以接受,但是近处的阴影却会显得非常块状。我们称之为透视锯齿(perspective aliasing)

我们需要给近处的阴影提供更高的分辨率,远处的可以分辨率低一些。我们可以根据距离使用不同的分辨率,解决方案就是为同一个光源渲染多张阴影贴图。我们在近处使用高分辨率阴影贴图,在远处使用低分辨率。这些阴影贴图称之为级联阴影(shadow cascade)

2.1 Cascade Amount

Unity通常为级联阴影数量提供三个选项:0、2、4。我们也一样,在MyPipelineAsset添加一个ShadowCascades枚举用于配置数量,默认为4。

2.2 Cascade Split

Untiy还允许指定级联在阴影距离中的分布情况。通过将整个阴影距离划分成二或四个部分来实现。如果是2个级联,就用一个值来决定在哪里划分两者。如果是四个级联,就用存储在向量中的三个值,将阴影距离划分成四个部分。我们使用与轻量级渲染管线相同的默认值。

但是Unity不会直接将这些值暴露在检视面板,而是显示一个特殊的GUI控件来允许你调整级联的区域。我们也来实现这种效果,先把这些属性隐藏起来。

我们需要创建一个自定义编辑器来显示联级划分的GUI,我们先创建一个最基础的。将它的脚本资源放在Editor文件夹中。获取三个相关属性,并绘制默认的检视器。我们还需要使用UnityEditor.Experimental.Rendering命名空间

在绘制默认检视器之后使用switch语句来决定我们绘制哪种级联的GUI。使用CoreEditorUtils.DrawCascadeSplitGUI 函数去绘制,之后调用序列化对象的ApplyModifiedProperties 方法来确保用户的修改可以应用到我们的资源中。

 MyPipeline只需要知道要使用多少级联以及他们的分布值是多少。我们可以使用单个三维向量同时处理二段和四段级联的分布数据。按要求添加字段和构造参数。

当MyPipelineAsset调用渲染管线的构造方法是,总是要求传入一个分布情况向量,即使实际是二段级联。这这种情况下,我们将唯一的分布值作为向量的第一个分量,另外两个设为0。

2.3 Cascades for Main Directional Light Only

我们不为所有的方向光都提供级联阴影功能,因为渲染多个阴影贴图性能消耗很大。我们将最明亮最重要的一个方向光源作为主光源,为其提供级联阴影,其他方向光只提供单阴影贴图。

主光源总是可见光列表中的第一个元素。我们可以在ConfigureLights中判断第一个光源是否符合标准,如果是方向光、阴影强度为正数,并且开启了阴影级联,那就说明是有效的主光源。我们用一个bool字段来记录这个情况。

我们会为主光源提供单独的渲染贴图,所以当我们拥有主光源时,让图块计数减1,并且在RenderShadows函数中将其从常规阴影贴图渲染中排除。

将级联阴影以tiles的形式渲染到一张单独的阴影贴图中,将其命名为_CascadedShadowMap。添加相关的标识符和字段。并在最后和其他阴影贴图一样释放纹理资源。

2.4 Reusing Code

渲染级联阴影和之前我们做的阴影渲染很相似,但是其中的差异还是有必要用一个单独的方法才能完成。然而这两个方法里许多代码都是重复的,我们把这部分代码重构成单独的方法。

首先是关于阴影渲染目标的设置,两者在这部分的代码是相同的。我们只需要用两个字段记录两者渲染目标对应的渲染纹理即可。

然后是设置阴影tiles。计算tiles偏移,设置视口以及剪裁,偏移值可以用二维向量返回值得到。

再然后,计算world-to-shadow矩阵这部分也可以放在一个单独的方法里,我们将视角和投影矩阵作为引用类型的参数传入,这样可以避免不必要的拷贝变量。同样,将world-to-shadow矩阵作为输出参数。

最后,调整RenderShadows函数使其使用重构后的函数。

2.5 Rendering Cascades

级联阴影的world-to-shadow矩阵需要单独存储在数组中,添加对应的字段,因为我们级联数量最多为4,所以数组大小设置为4。

创建一个RenderCascadedShadows方法,首先复制RenderShadows的代码。接下来就简单了,我们不需要考虑聚光源并且只会用到第一个光源。我们不需要处理每个光源的阴影数据,而且阴影设置肯定是开启级联的。级联不是四段就是两段,也就是说阴影贴图总是分为四个tile。

在调用ComputeDirectionalShadowMatricesAndCullingPrimitives时,我们光源序列为0,并使用for循环的迭代值作为级联序列。在这里我们就需要提供实际的级联数量和分布向量了。最后,我们再把图块的坐标转换附加到world-to-shadow中,在tile界限范围内渲染阴影是之后shader能正确采样到级联阴影的重要前提。

在ConfigureLights后,如果有主光源调用该函数

现在我们最终可能有0张,一张或者两张渲染纹理。如果只有主光源,只需要渲染级联阴影贴图。如果有另外带阴影的光源还需要渲染常规的阴影贴图。或者我们有阴影但没有主光源,那我们就只需要常规阴影贴图。如果你在frame debugger中检查级联阴影贴图,你会看到它由四个图块组成。它们内容是否可见取决于阴影距离和级联分布。

2.6 Sampling the Cascaded Shadow Map

在shader里使用级联阴影贴图,需要做一些事。首先,我们得知道使用软阴影还是硬阴影的方式采样贴图,这一点我们可以通过shader关键字来控制。我们使用两个关键字来区分级联的软硬阴影,省去了在shader中创建分支的需要。

接下来我们需要知道阴影贴图的尺寸和阴影强度,虽然我们可以直接用_ShadowMapSize但是为了让shader能分开处理两者的大小,我们使用单独的_CascadedShadowMapSize 来表示。

在RenderCascadedShadows函数末尾设置这些值和关键字。

同样也需要在RenderCascadedShadow 没有被调用的情况下关闭级联阴影的关键字

Lit shader中为级联阴影关键字添加多重编译指令。共有三个选项:无/级联软阴影/级联硬阴影。

之后向shadow buffer中添加所需的变量,定义级联阴影贴图纹理和采样器

添加一个表明是否采样级联阴影的bool参数来使HardShadowAttenuation既可以用于常规的阴影采样也可以用于级联阴影,参数默认为false。用这个bool值来决定具体使用哪张纹理和采样器。我们使用的bool参数是硬编码的,也就是说在实际编译时并不会产生条件分支。

SoftShadowAttenuation 也一样,不过在这里只需要选择正确的纹理就好了,其余的由HardShadowAttenuation 函数完成,没必要再写一遍。

创建一个CascadedShadowAttenuation 方法,他就像ShadowAttenuation的简化版。如果没有级联阴影,衰减直接设为1,反之才会计算阴影位置获取软硬阴影的衰减值并应用应用强度。

选择正确的级联阴影贴图是下一节介绍的内容,这一节我们先硬编码统一使用第三张级联阴影贴图,也就是使用_WorldToShadowCascadeMatrices 中序列为2的转换矩阵。如果你用的是四段级联,使用第三张贴图可以让我们看到大部分区域的阴影。如果用第四张的话区域是大了,但是近处的阴影分辨率太低,影响观察。

接下来,创建一个MainLight函数来计算主光源,它和DiffuseLight方法做的事一样,但是限制了只计算索引为0的方向光,并且使用CascadedShadowAttenuation 来获取阴影

如果有级联阴影,就把主光源也加入LitPassFragment 计算漫反射总和中。 

主光源的级联阴影现在终于能够看到了,但是主光源在光照循环中被计算了两次,这是错误的。我们不能简单地跳过循环中的第一个光源,因为对每个物体而言,无法确保主光源就是最重要的那个光源。对此我们要么在shader的循环中添加分支,要么渲染前就干脆将主光源移出可见光列表。我们选择后者,修改中ConfigureLight 的光源数量。这样的副作用就是当我们有主光源时,像素光数量上限变成了5个。

从可见光列表中移除主光源的问题是如果我们使用了级联阴影,每一帧都会修改可见光列表,从而导致临时内存的分配。现在也没什么好办法,除非以后会出一个不会分配新数组的GetLightIndexMap 方法。

2.7 Selecting the Correct Cascade

现在主光源的级联阴影贴图终于能用了,但用的都是同一级别的级联贴图。第三张级联贴图对于远处的阴影效果挺好,但是对于近处效果就很差。而第二张级联贴图恰恰相反,近处表现的很好,但是范围实在太小了,远处根本没阴影。

Unity使用级联分段值划分每个级联贴图负责的阴影空间区域。它使用一个剔除球体来定义每个级联贴图的范围。剔除球的半径依次增加,球的位置也同样。想知道我们使用哪一等级的级联贴图,我们就得找出片元处于哪个剔除球内部。

我们要把剔除球的信息传给shader。使用数组是最方便的方法。在MyPipeline中添加对应的标识符和字段。用四维向量表示每个球。xyz分量描述球的位置。w分量定义球的半径。

RenderCascadedShadows函数里我们可以获取每个级联的剔除球。我们只需要简单的把它拷贝到我们的数组然后再传给shader就ok了。因为在判断片元位于哪个剔除球时只会用到半径的平方,所以我们传入半径的平方来减少shader的运算。

shader中,将剔除球数组变量添加到阴影缓冲区

 创建一个很便捷的方法,用于判断一个点是否在剔除球体内。

在CascadedShadowAttenuation里为四个剔除球各调用一次这个方法。返回1表示该点位于剔除球内,返回0就在球外面。返回值就是表示这些球是否有效的标志。在确定级联等级前将这四个值放在一个flaot4类型变量中。

一点位于一个球的同时,还躺在更大的球里面。我们最终可能得到五种情况: (1,1,1,1), (0,1,1,1), (0,0,1,1), (0,0,0,1),(0,0,0,0)。我们将这四个值加起来除以四得到的值返回来观察级联层次。也就是点乘¼。

我们使用第一张符合要求的贴图(所渲染的点所在范围最小的级联贴图),也就是说我们需要把其对应标志位后边的标志值清零。

 

一个点至少在一个剔除球里面时,结果是没问题的,但点如果在所有剔除球外面,结果为0,会错误的采样了第一张级联阴影贴图。Unity在这里用了一个小技巧,它在world-to-shadow中添加一个零矩阵作为第五个数组元素来表示不存在的那个联级贴图。零矩阵会将阴影位置转换到近平面,自然就不可能产生阴影了。我们也这样做,为MyPipeline的worldToShadowCascadeMatrices 数组添加第五个元素。

 然而,如果z缓冲区反转,那我们就得将阴影空间的z坐标设为1才能表示近平面,我们在构造函数把这个矩阵的m33字段改为1即可。

增加shader中对应数组的长度,并完成(0,0,0,0) → 4的转换,我们该为将值和(4,3,2,1)点乘,让4减去它来得到级联等级

我们可以混合级联贴图吗?

和Unity的渲染管线一样,我们直接选择一个级联贴图采样。结果可能在每个级联之间会有不连续的图像。也就是阴影的像素突然发生变化。你也可以定义一个过渡区域,并在其中对两个相邻的级联贴图插值。这要求我们寻找两个级联贴图的序列,一个混合因子,以及双倍的阴影采样。

因为剔除球不会与相机和阴影距离对齐,所以级联阴影不会和其他阴影一样在同一距离消失。我们也一样可以在CascadedShadowAttenuation 中检查阴影距离来实现统一的效果。

Unity采样级联阴影贴图时,不是应该用一个屏幕空间的pass吗?

没错,Unity使用一个单独的屏幕空间pass,将级联阴影渲染到另一张纹理中去。这其实和我们做的一样,只不过它会有一个整体的显示。以便在forward pass的每个片元中采样其中的阴影数据。屏幕空间pass会比较迂回地完成这些工作,而逐片元的计算方式则更为直白简单,这也是我为什么会选择这种方法作为教程教学。

使用单独的全屏pass的一个原因是可以更快的采样阴影。在有大量重复绘制的情况下,效果会更好,因为此时可能会有多个片元对同一个位置采样。通过增加一个仅深度的pass存入深度缓存,来消除不透明物体的重复绘制以减少计算量。屏幕空间阴影的方法总是需要一个depth-only 的pass来提取片元的深度值。

另一个原因则是因为Unity的旧版渲染管线可以用它展现高质量的软阴影滤波结果。但是在轻量级渲染管线里就用不到了,他对于所有的阴影采样都使用相同的代码。

哪个方法最好呢?你可以自己测试这三种情况:逐片元,depth-only 的逐片元,以及depth-only 的屏幕空间

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浅析Unity中的Enlighten与混合光照

原文https://www.cnblogs.com/murongxiaopifu/p/8553367.html 0x00 前言 在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten【1】来提供实时全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapper——Progressive来提供烘焙全…

聊聊LightProbe原理实现以及对LightProbe数据的修改

原文链接https://www.cnblogs.com/murongxiaopifu/p/8997720.html 0x00 前言 最近工作比较忙,所以文章已经很久没有更新了。这篇小文的主题也是在出差的高铁上想到,因为最近和一些朋友聊天,发现他们中很多人的项目中都使用了多个实时光源。…

3D游戏的照明设计理论,第3部分:三点照明法的异端与误区

https://zhuanlan.zhihu.com/p/87997570 这是有关如何处理游戏照明的系列文章的一部分。第一部分是关于灯具,第二部分是关于光的形式材料。 在第一部分中,我们首先从文化角度考虑了灯光-灯光在整个历史上对不同的人意味着不同的事物,并且在照…

3D游戏的照明设计理论,第4部分:如何在游戏引擎中照亮游戏世界

从更一般和更概念的角度来看,这是有关我如何处理游戏照明的系列文章的一部分。我在Unity中构建了大部分示例,但这通常适用于任何3D游戏引擎,其中大多数具有类似的照明工具。 我们开始思考了有关光照的文化和概念,在第一部分。在第…

unity shader 变种(多重编译 multi_compile)

一、定义 在unity中我们可以通过使用#pragma multi_compile或#pragma shader_feature指令来为shader创建多个稍微有点区别的shader变体。这个Shader被称为宏着色器(mega shader)或者超着色器(uber shader)。实现原理:…

AndroidStudio导出aar文件给Unity使用

AndroidStudio导出aar文件给Unity使用 本文参考 :http://www.devacg.com/?post548 Demo地址:https://github.com/JulyNine/AndroidToUnity 一、用Android Studio创建个空工程 注意:包名要与Unity中工程的包名不一致,不然打包时…

Unity C# Job System介绍(四) 并行化Job和故障排除(完结)

并行化job ParallelFor jobs​docs.unity3d.com 当调度Jobs时,只能有一个job来进行一项任务。在游戏中,非常常见的情况是在一个庞大数量的对象上执行一个相同的操作。这里有一个独立的job类型叫做IJobParallelFor来处理此类问题。ParallelFor jobs当调…

C# Job System

概述 设计目的:简单安全地使用多线程,随便就能写出高性能代码 收益:FPS更高,电池消耗更低(Burst编译器) 并行性:C# Job System和Unity Native Job System共享工作线程worker threads&#xf…

Unity游戏开发——C#特性Attribute与自动化

这篇文章主要讲一下C#里面Attribute的使用方法及其可能的应用场景。 比如你把玩家的血量、攻击、防御等属性写到枚举里面。然后界面可能有很多地方要根据这个枚举获取属性的描述文本。 比如你做网络框架的时候,一个协议号对应一个类的处理或者一个方法。 比如你做…

Unity c#中Attribute用法详解

举两个例子,在变量上使用[SerializeFiled]属性,可以强制让变量进行序列化,可以在Unity的Editor上进行赋值。 在Class上使用[RequireComponent]属性,就会在Class的GameObject上自动追加所需的Component。 以下是Unity官网文档中找…

走进LWRP(Universal RP)的世界

走进LWRP(Universal RP)的世界 原文:https://connect.unity.com/p/zou-jin-lwrp-universal-rp-de-shi-jie LWRP自Unity2018发布以来,进入大家视野已经有一段时间了,不过对于广大Unity开发者来说,依然相对…

Unity 2017 Game Optimization 读书笔记(1)Scripting Strategies Part 1

1.Obtain Components using the fastest method Unity有多种Getcomponet的方法&#xff1a; GetComponent(string), GetComponent<T>() GetComponent(typeof(T)) 哪种效率最高会跟随Unity版本的变化而变化&#xff0c;对于Unity 2017&#xff0c;本书作者的测试是Ge…

C# 多态相关的文章

一 C# 多态的实现 封装、继承、多态&#xff0c;面向对象的三大特性&#xff0c;前两项理解相对容易&#xff0c;但要理解多态&#xff0c;特别是深入的了解&#xff0c;对于初学者而言可能就会有一定困难了。我一直认为学习OO的最好方法就是结合实践&#xff0c;封装、继承在…

C++ 虚函数和虚表

几篇写的不错的文章&#xff0c;本文是整合了这几篇文章&#xff0c;感谢这些大佬 https://www.jianshu.com/p/00dc0d939119 https://www.cnblogs.com/hushpa/p/5707475.html https://www.jianshu.com/p/91227e99dfd7 多态: 多态是面相对象语言一个重要的特性,多态即让同一…

Unity 2017 Game Optimization 读书笔记(2)Scripting Strategies Part 2

1. Share calculation output 和上一个Tip很像&#xff0c;可以缓存计算结果或者各种信息&#xff0c;避免多次重复的计算&#xff0c;例如在场景里查找一个物体&#xff0c;从文件读取数据&#xff0c;解析Json等等。 容易忽略的点是常常在基类了实现了某个方法&#xff0c;在…

Unity 2017 Game Optimization 读书笔记(3)Scripting Strategies Part 3

1.Avoid retrieving string properties from GameObjects 通常来讲&#xff0c;从C#的object中获取string 属性没有额外的内存开销&#xff0c;但是从Unity中的Gameobject获取string属性不一样&#xff0c;这会产生上一篇讲到的 Native-Managed Bridge&#xff08;Native内存和…

Unity 2017 Game Optimization 读书笔记(4)Scripting Strategies Part 4

1.Avoid Find() and SendMessage() at runtime SendMessage() 方法和 GameObject.Find() 相关的一系列方法都是开销非常大的。SendMessage()函数调用的耗时大约是一个普通函数调用的2000倍&#xff0c;GameObject.Find() 则和场景的复杂度相关&#xff0c;场景越复杂&#xff0…

Unity HDRP中的光照烘焙测试(Mixed Lighing )和间接光

部分内容摘抄自&#xff1a;https://www.cnblogs.com/murongxiaopifu/p/8553367.html 直接光和间接光 大家都知道在Unity中&#xff0c;我们可以在场景中布置方向光、点光、聚光等类型的光源。但如果只有这些光&#xff0c;则场景内只会受到直接光的影响&#xff0c;而所谓的…

聊聊Unity项目管理的那些事:Git-flow和Unity

感谢原作者https://www.cnblogs.com/murongxiaopifu/p/6086849.html 0x00 前言 目前所在的团队实行敏捷开发已经有了一段时间了。敏捷开发中重要的一个话题便是如何对项目进行恰当的版本管理。项目从最初使用svn到之后的Git One Track策略再到现在的GitFlow策略&#xff0c;中…

聊聊网络游戏同步那点事

写的非常好的一篇博文&#xff0c;转载自https://www.cnblogs.com/murongxiaopifu/p/6376234.html 0x00 前言 16年年底的时候我从当时的公司离职&#xff0c;来到了目前任职的一家更专注于游戏开发的公司。接手的是一个platform游戏项目&#xff0c;基本情况是之前的团队完成…