Unity自定义SRP(五):烘培光

   更新日期:2024.05.22
https://catlikecoding.com/unity/tutorials/custom-srp/baked-light/

​ 到目前为止我们都是在实时渲染光照,除此之外还可以提前计算好光照,然后存储在灯光贴图和探针中,这么做的好处是可以减少实时计算耗费的时间,还可以添加无法实时计算的间接光照,即全局光照,不过烘培光照会提升内存占用。

​ 在Unity的 Window/Rendering/Lighting Settings 中我们可以通过开启 Mixed Lighting 下的 Baked Global Illumination 来设置烘培光,光照模式目前设置为 Baked Indirect :

​ 在 Lightmapping Settings 中可以对灯光贴图进行相关设置。

​ 为使用烘培光,我们需要将 Light 组件下的 Mode 设置为 Mixed 。

​ 在物体的 Mesh Renderer 下的 Lighting 设置中,我们可以开启 Contribute Global Illumination ,并将模式修改为 Lightmaps ,即间接光接触到这些表面时,会将光照信息烘培到灯光贴图中。

​ 在 Lightmapping 下的 Baked Lightmap 中我们可以看到灯光贴图。

​ 使用完全烘培光,我们将模式设置为 Baked ,这样的话就无法使用实时光。

​ 创建 GI.hlsl ,定义一个 GI 结构体,目前先包含漫反射属性,并创建一个 GetGI 方法来获得全局光照信息:

​ 在 GetLighting 中先利用GI初始化颜色:

​ 在片元着色器中应用:

​ 为了获得灯光贴图UV坐标,Unity需要将其送往shader。我们需要指示管线对每个使用灯光贴图的物体进行此操作,可以在 CameraRenderer.DrawVisibleGeometry 中设置 drawSettings 的 perObjectData 属性,这里设置为 PerObjectData.Lightmaps :

​ Unity现在会为开启 LIGHTMAP_ON 关键字的shader变体渲染应用灯光贴图的物体:

​ 灯光贴图的UV坐标是顶点属性的一部分,在 Attributes 中使用 GI_ATTRIBUTE_DATA 宏定义,在 Varyings 中使用 GI_VARYINGS_DATA 定义,在顶点着色器中,使用 TRANSFER_GI_DATA 进行转换:

​ 在片元着色器中获取UV,使用 GI_FRAGMENT_DATA 宏:

​ 实际上上面这些宏没什么意义,我们需要在 GI.hlsl 中定义,如果开启 LIGHTMAP_ON ,我们才为宏赋予意义:

​ 灯光贴图坐标通常由Unity逐网格自动生成,或者是导入网格数据的一部分。网格会进行纹理展开,这样就可以映射到纹理坐标,这个展开操作会在灯光贴图中逐物体的进行缩放和平移,所以每个实例会有自己的空间。

​ 灯光贴图的UV变换是 UnityPerDraw 缓冲的一部分,我们添加下面两个变量:

​ 然后调整 TRANSFER_GI_DATA 宏,应用变换操作:

​ 我们需要运用到 Core RP 中的 EntityLighting.hlsl 。定义纹理和采样器:

​ 定义采样方法 SampleLightMap ,调用 SampleSingleLightmap 方法:

​ SampleSingleLightmap 方法除UV外要求多个参数,首先需要传入纹理和采样器状态,我们可以使用 TEXTURE2D_PARAM 宏组合:

​ 在UV后是缩放和平移变换,由于已经做过,这里设为单位变换即可:

​ 然后是指示灯光贴图是否被压缩,如果定义了 UNITY_LIGHTMAP_FULL_HDR 的话就要设为false,最后的参数包含解码指令:

​ SampleSingleLightmap :

​ 动态物体并不会影响烘焙的全局光照,但可以通过光照探针影响。光照探针是场景中的一个点,通过一个三次多项式,特别是L2球面谐波来近似烘培所有的入射光。光照探针可以拜访在场景周围,Unity会逐物体对这些探针插值来达到近似的光照结果。

​ 光照探针通过创建光照探针组来添加,通过 GameObjectLight/Light Probe 。默认是包含个探针的立方体。

​ 场景中可以有多个探针组,Unity将所有的探针组合在一起,然后创建一个四面体网体来连接所有探针。每个动态物体处在一个四面体网格中。四面体的四个顶点的探针会被插值,获得最终光照后应用到物体上。如果一个物体位于探针覆盖区域范围外,会使用最邻近的三角形,这样光照会看起来很奇怪。

​ 默认情况下,当一个动态物体被选中后,会显示哪些影响它的探针,以及一个插值后的位置。

​ 如何拜访光照探针取决于场景。首先,只有动态物体才需要探针;其次,光照变化的地方也可以摆放探针,每个探针是插值的终点,因此将它们围绕着光照过渡的地方拜访;第三,不要再烘培几何体内摆放探针,这样会变黑;最后,插值是会遍历所有物体的,因此,当光照在一个物体的对立面不同时,探针要尽可能的靠近两面。

​ 同理,探针插值数据需要送往GPU,这也是一个逐物体数据:

​ shader中我们需要的数据如下:

​ 在 GI 中采样光照探针,定义 SampleLightProbe 方法:

​ SampleSH9 需要探针数据和法线方向:

​ 球面谐波相关介绍略。

​ 在 GetGI 中应用:

​ 光照探针对小的动态物体比较好使,但因为光照时基于单个点的,因此对于更大的物体就不好使了。

​ 对于这些大物体,我们可以添加 LightProbeProxyVolume 组件,简称LPPV,这样就可以匹配大物体。

​ 同理,配置逐物体数据属性:

​ shader中,我们需要下面这些数据:

​ 体数据存储在3D纹理中, unity_ProbeVolumeSH ,在 GI 中定义:

​ 是使用LPPV还是插值的光照探针,取决于 unity_ProbeVolumeParams 的第一个组件。采样探针代理体我们使用 SampleProbeVolumeSH4 方法,参数依次是纹理和采样器,世界空间位置,世界空间法线, unityProbeVolumeWorldToObject 矩阵, unity_ProbeVolumeParams 的YZ组件,然后是SizeInv和Min的xyz组件:

SampleProbeVolumeSH4 :

​ 因为间接漫反射光与表面作用后应该会会被表面的漫反射率影响,对此,Unity使用一个特殊的meta pass在烘培时来决定反射光 。

​ 新建一个 LitInput.hlsl 文件,将变量放入,避免重复声明。同时构建一些获取属性的方法,隐藏Unity自带的宏:

​ 在shader的开头,我们包含这些公用文件:

​ Meta Pass的Light Mode我们设置为 Meta :

​ 接着构建最基本的顶点和片元着色器。 ZERO_INITIALIZE 可用于初始化结构体变量:

​ 定义光照贴图UV,将其作为局部空间坐标的XY组件:

​ OpenGL需要精确配置局部坐标的Z组件:

​ meta pass用于生成不同的数据,通过 unity_MetaFragmentControl 通信控制:

​ x组件控制漫反射:

​ Unity的meta pass会将meta值加上通过粗糙度控制的镜面反射率的一半,用于提亮,让高光反射但粗糙的物体也可以传递一些间接光:

​ 之后,结果通过一个幂运算提升:

​ 之后,在 GetLighting 中应用表面漫反射率:

​ 在shader中添加新的属性:

​ 在 LitInput 中声明对应的属性和方法:

​ 在片元着色器末尾调用:

​ 在meta pass中,使用 unity_MetaFragmentControl 的y组件控制发光:

​ 在 CustomShaderGUI 中,我们需要手动开启选项:

​ 这样就会出现选项:

​ 使用 Baked 表明烘培发光。

​ 但Unity尽量在烘培时避免额外的发光pass,如果材质的发光被设为0就会被忽略。为此,在发光模式变化时,我们可以使用 MaterialGlobalIlluminationFlags.EmissiveIsBlack 来重写 globalIlluminationFlags ,这样,只有在要烘培时才会开启:

​ Unity的Lightmapper对透明使用硬编码方法,即硬性规定使用 _MainTex 、 _Color 、 _Cutoff ,目前我们只支持了 _Cutoff ,为此,需要额外定义两个属性,并打上 [HideInInspector] 标签:

​ 我们需要确保 _MainTex 与我们的 _BaseMap 对应,我们定义一个 CopyLightMappingProperties 方法来进行属性复制:

​ 不过,这也就意味着烘培透明物体只能依赖于单张纹理、颜色和裁剪属性,同时lightmapper也只考虑材质的属性,逐实例属性不考虑。

  • 17098515924 :Unity自定义SRP(五):烘培光
    危胜要2679 :答:​ 体数据存储在3D纹理中, unity_ProbeVolumeSH ,在 GI 中定义: ​ 是使用LPPV还是插值的光照探针,取决于 unity_ProbeVolumeParams 的第一个组件。采样探针代理体我们使用 SampleProbeVolumeSH4 方法,参数依次是纹理和采样器,世界空间位置,世界空间法线, unityProbeVolumeWorldToObject 矩阵, unity_ProbeVolumeParam...
  • 17098515924 :从零开始的SRP
    危胜要2679 :答:Unity的SRP(Scriptable Render Pipeline)革命性地重塑了渲染流程,通过C#指令的灵活性掌控每一步,让自定义渲染和平台优化变得更加可能。让我们一步步深入了解这个强大的工具。入门SRP首先,要在Project Settings/Graphics中启用SRP。找到RenderPipelineAsset字段,填入SampleRenderPipelineAsset。创建这个类,扩展Re...
  • 17098515924 :如何自定义unity界面布局并保存
    危胜要2679 :答:1、根据查询中国数码网显示,打开Uitiy3D软件。2、调整自己的输入自己的界面布局。方法比较简单鼠标进行拖拽即可。3、在软件界面的右上角(关闭按钮的下方),点击layout(界面)的下拉箭头。弹出选项中的savelayout(保存界面选项)输入命名,就可以生成这个界面的布局。
  • 17098515924 :unity游戏自定义分辨率
    危胜要2679 :答:1、打开Unity,新建一个空工程,Unity界面。2、在工程中新建一个脚本,脚本可以命名为“ScreenWHTest”。3、选中“ScreenWHTest”脚本,双击脚本或者右键“Open C# Project”,打开脚本。4、在打开的“ScreenWHTest”脚本上进行编辑,首先获取当前屏幕的宽与高,然后把获取到的宽与高打印在控制台console上...
  • 17098515924 :Unity 渲染系列__01__着色器(Shader)基础
    危胜要2679 :答:自定义Shader之旅:创作你的第一个Shader——My First Shader,从零开始编写并掌握自定义渲染逻辑。2. Shader实战从Unity的默认场景出发,我们创建一个新的材质,选择自定义Shader路径,将球体材质切换为自定义,感受Shader带来的色彩变化。SubShader是Shader的核心部分,包含多个Pass,每个Pass处理不同的渲染...
  • 17098515924 :Unity 编辑器扩展二 Editor 自定义Inspector面板
    危胜要2679 :答:OnInspectorGUI()是Unity的Editor类里的相关函数,通过对该方法的重写,可以自定义对Inspector面板的绘制。这里要先创建Test1脚本,再创建Test1Editor,否则引用会报错。以下参考 【Unity 编辑器】扩展总结三:自定义Inspector面板 Unity Editor 基础篇(二):自定义 Inspector 面板 Unity检视面板重构...
  • 17098515924 :unity五种数据储存方法——ScriptableObject
    危胜要2679 :答:。这类似于插槽设计模式,ScriptableObject提供一些槽,MonoBehaviour可以把自己插进去。适用于AI类型、回血的buff或debuffs等(回血例子见结尾)如何实现? step1.创建你用于共享数据的类(例如EnemyData)step2.新建一个脚本扩展Editor,使编辑器能够创建自定义的ScriptableObject对象 step3. 在需要引用的脚...
  • 17098515924 :URP技术:为游戏画面效果带来突破性提升
    危胜要2679 :答:URP的强大特性</SRP/URP的基础架构,构建了灵活的可编程渲染管线,无论是2D、3D、AR还是VR,都能得心应手地定制。其核心优势在于自定义Pass,赋予开发者无限可能。从内置到URP的无缝转换,虽然核心自动升级,但自定义Shader的调整需要开发者亲手操作,以保持项目的连贯性。URP的适用范围广泛,从手机游戏...
  • 17098515924 :SRP Batching & GPU Instance
    危胜要2679 :答:GPU Instance 也可以将属性写在 UnityPerMaterial 中,并且 SRP Batching 优先级比 GPU Instance 高,所以如果没有通过 MaterialPropertyBlock 修改属性的话,会优先使用 SRP Batching。如果属性写在自定义名称中,则不会启用 SRP Batching。 GPU Instance 有两种用法。一是直接修改个别物体的属性...
  • 17098515924 :如何制作Unity3D自定义图片按钮
    危胜要2679 :答:2.爆炸用引擎自带的粒子系统做,那样最方便,不过你得有爆炸的图片才行,粒子系统支持图片的拆分,也就是说你可以在一张图片上将动画的各个帧以矩阵排列,然后每个粒子片都可以有动画的效果。3.你可以用脚本自定义角色的控制方式,角色碰撞用Charactor Controller(其他不适用于人物,除非你能自己写脚本控制...
  • 相关链接

    欢迎反馈与建议,请联系电邮
    2024 © 视觉网