彻底弄懂Unity3D的光照模式,光照贴图和光探针(持续更新)

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 1 光源的Light Mode 光源的Light Mode分为Realtime,Baked,Mixed四种。 Realtime类型 本类型的光源,会根据Shadow Distance项指定的值,以及当前摄像机的位置值,去敲定本光源是否给物体投下阴影。在URP中,Shadow Distance值在Universl Render Pipeline Asset中指定。 在旧管线中,如果启用了【Realtime Global Illumination】选项,realtime光源仅贡献实时的直接光照部分。正因为如此,所以由这种光源产生的影子是纯黑的,不会受别的间接光照的影响 在自定义的管线中,实时光源可以对实时的间接光照部分产生贡献。 Baked类型 Unity把Baked类型的光源产生的照明和阴影信息,烘焙到lightmap或者light probe中。 baked类型的光源,只贡献了漫反射部分的光照,不贡献镜面高光部分的光照。 只有标识为static的GameObject才接受baked类型的光源产生的照明和阴影。 Mixed类型 mixed类型,顾名思义,即是整合了realtime和baked两种模式的特点。采用mixed类型的光源,可以在其贡献的直接光照部分,使用realtime的模式实现,间接光照部分,使用baked模式实现。 在场景中,mixed类型的光源的行为,依赖于【Lighting】窗口中的【Lighting Mode】属性设置。不同的设置,会产生不同的视觉保真度,以及产生不同的性能消耗。 在运行时,可以更改mixed类型的光源的属性。但仅对realtime部分的属性生效。 2【Lighting】窗口中的【Lighting Mode】属性 直接光照的实现模式 间接光照的实现模式 阴影的实现模式 适用机型 Baked Indirect real-time baked real-time 中端机型 Shadowmask real-time baked 部分baked,部分real-time 中高端机型 Subtractive baked baked 只对一个平行光渲染real-time阴影 低端机型 Baked Indirect光照模式的一些细节 内置管线,URP,HDRP,都支持本模式 在本模式下,Mixed类型的光源照射到GameObject时,GameObject会收到以下的光影信息如下表: Shadowmask光照模式的一些细节 与baked indirect模式类似,Shadowmask模式也结合了实时直接光照和烘焙间接光照。但两者不同之处在于在于渲染阴影的方式。Shadowmask模式允许Unity在运行时结合baked阴影和real-time阴影,并在远处渲染阴影。它通过使用额外的光照贴图 纹理称为阴影蒙版,并通过将附加信息存储在光探头。 Shadowmask模式提供所有模式下保真度最高的阴影,但性能成本和内存要求最高。 不同渲染管线对Shadowmask模式的支持程度 管线类型 是否支持 内置管线 支持 URP 从10.1版本开始支持 HDRP 支持 Shadowmask模式有两种,一种是Distance Shadowmask,另一种是Shadowmask。在Project Setting界面的Quality选项可以指定,如下图所示:

Unity动态加载光照贴图的坑

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com Unity的光照贴图,如果在运行时动态加载的话,需要对创建出来的game object的lightmap index做一次重新指派, 然后在设置一下LightmapSetting。基本按照Mr.钱康来的这一系列文章那样子设置。如下链接: Unity中光照贴图一二坑及解决办法 Unity中光照贴图一二坑(续) 如果按照老钱的方法去做了,还是有问题的话,那么就要看下 【Project Settings -> Graphics -> Shader Stripping】 菜单下的这个: 就是打包时没把LIGHTMAP_ON相关的shader变体给打进去,因为被strip掉。为了保险,选中Custom,然后所有全部选上,再进行打AB。就能正确加载光照贴图。当然,这样子会导致变体变多变大,所以最好还是仔细分析下,那些勾选上为好。 国内有一个兄弟也是碰到这个问题,在Unity论坛上也有人用这个方案解决了问题 另外,经过实测,只要正确设置好shader stripping之后,无论从AB中装载进来的game object,是不是从static变为非static标签,或者有没有用StaticBatchingUtility.Combine去运行时静态合批,都不影响正确加载lightmap 参考网页 光照贴图接缝探讨 where did “lightmap static” go 打包Assetbundle以及Shader Stripping导致LightMap全部丢失的解决方法 UWA上的《Lightmap丢失》 Shader Variants 打包遇到的问题 Stripping scriptable shader variants Stripping commonly unused shader variants in Unity’s built-in render pipeline Unity帮助文档中和Shader Stripping相关的页面

Unity卡通渲染知识点笔记(持续更新中)

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 描边 描边有两种方法,一种是用两个pass,第一个pass绘制模型本身,第二个pass则是绘制边缘。这种技术的要点是在第一个pass使用cull back把背面拣选掉,第二个pass使用cull front 把正面拣选掉,这时候就只剩下侧边的边缘线颜色。 在第二个pass中,在绘制时,让模型顶点沿着法线方向向外移动一定的距离。这时候绘制出的一个纯色模型把原来的模型给包住。但如果是在世界空间中移动的话,当镜头拉远时,描边线会变得很细小。所以为了解决这个问题,一般将法线在裁剪空间中或者在NDC空间中做位移: 在裁剪空间中做位移的操作如下: // 这段代码是一段URP代码 Varyings vert(Attributes input) { // scaledScreenParams 是用当前窗口的屏幕宽高像素值乘以渲染缩放系数renderScale的值。renderScale默认为1, float4 scaledScreenParams = GetScaledScreenParams(); float aspect = abs(scaledScreenParams.x / scaledScreenParams.y);//求得X因屏幕比例缩放的倍数 // 下面的计算是在裁剪空间中操作。当然也可以直接将法线转到NDC Varyings output; VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS); float3 normalCS = TransformWorldToHClipDir(normalInput.normalWS);//法线转换到裁剪空间 float2 extendDis = normalize(normalCS.xy) *(_OutlineWidth*0.01);//根据法线和线宽计算偏移量 extendDis.x /= aspect ;//由于屏幕比例可能不是1:1,所以偏移量会被拉伸显示,根据屏幕比例把x进行修正 output.positionCS = vertexInput.positionCS; // 因为后续会转换成NDC坐标,会除w进行缩放,所以先乘一个w,那么该偏移的距离就不会在NDC下有变换 output.positionCS.xy += extendDis * output.positionCS.w ; // 要预先乘一个做透视除法的值 return output; } 在NDC空间做变换代码如下: // 这是一段基于Unity内建管线的顶点着色器代码 v2f o; UNITY_INITIALIZE_OUTPUT(v2f, o); float4 pos = UnityObjectToClipPos(v.

URP和内建管线的一些编程上的差异

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com SubShader代码中的Tags 新增加了RenderPipeline关键字 SubShader的Tags段中需添加 "RenderPipeline" = "UniversalPipeline"语句段 光照模式(LightMode)关键字的对应替换 Built-in URP 作用 ForwardBase UniversalForward ForwardAdd 开启关键字_ADDITIONAL_LIGHTS解决 ShadowCaster ShadowCaster MotionVectors 尚未支持 Always 不再支持 PrepassBase 不再支持 PrepassFinal 不再支持 Vertex 不再支持 VertexLMRGBM 不再支持 VertexLM 不再支持 URP新增 DepthOnly URP新增 Meta 用于烘焙光照贴图 URP新增 Universal2D 用于2D的前向渲染 URP新增 UniversalGBuffer Deferred Rendering(延迟渲染)中使用,目前URP不支持延迟渲染,暂时用以兼容HDRP URP新增 UniversalForwardOnly 用于在Deferred Rendering(延迟渲染)中,表示这个Pass使用Forward Rendering(前向渲染) 变体相关的指令 内建管线中,提供了multi_compile_fwdbase来编译所有ForwardBasePass所需要的变体,multi_compile_fwdadd来编译ForwardAddPass所需要的所有变体,类似如下代码: #pragma multi_compile_fwdbase 而在URP中,需要自己判断需要编辑哪些变体,用户又更大的灵活性,类似如下(参考Lit.Shader): #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE 参考网页 从 Builtin 管线升级到 URP

Scriptable Render Pipeline (SRP) Batcher

非SRP Batcher的Unity渲染管线怎么做 不多说,先看图: 图中有个Unity Engine propeties,其实就是指一些不需要我们显式地写在shaderlab代码的Propeties块中的uniform shader变量。比如物体的变换矩阵等等。 上图中的Unity Engine properties,以及各个材质球数据,存放在System Memory中。每当准备渲染物体时。CPU要将这些数据从System Memory中搜集起来,设置到shader的常量缓冲区中去(即CBUFFER,即从CPU传给GPU的数据,这些数据包含了shaderlab代码的Propeties块中的定义的变量)。在内部的渲染循环中,当渲染某个物体,发现需要用到一个新的材质数据时,CPU就将shader properties搜集起来。放到不同的常量缓冲区中去。这些常量缓冲区的个数,就取决着色器代码中声明了多少个。 SRP Batcher 的工作原理: 在 Unity 中,您可以在一帧中的任何时间修改任何材质的属性。然而这种做法有一些缺点。例如,当在一次DrawCall调用种使用新材质时,有很多工作要做。因此,场景中的材质越多,Unity设置 GPU用到的数据所需要的 CPU时间就越多。传统的处理方式是减少DrawCalls的数量来优化CPU端的渲染成本,因为Unity在发出DrawCall之前要设置很多东西。真正的 CPU耗时是耗在这些设置操作,而不是来自 GPU的绘制本身。这些设置操作也只是Unity 需要推送到 GPU 命令缓冲区的一些字节数据而已。 当场景中有大量的材质球,但是shader的变体比较少时,SRP Batcher就能进行优化。它的方法简而言之是:对Unity Engine properties,尽可能将其留存在GPU memory中。如果材质的内容没有发生变化的话,那么就不需要把这些数据上传到GPU memory上,从而省去了传统方式中的这部分CPU的工作。SRP Batcher专门定制了一些代码(dedicated code),可以快速地将Unity Engine properties更新到一个大的GPU 缓冲区(large GPU buffer) 中。如下图所示: 在上图中,CPU仅仅需要处理built-in engine properties,也就是诸如物体的变换矩阵等等。这是因为物体可能会移动,所以它的世界变换矩阵等等会经常发生变化。而其他的材质数据就被持久化地存储在CBUFFER中,这是因为大部分可渲染物体,它进行渲染时,传给shader的一些uniform变量一般都是保持,不随着时间的变化而变化的。这也就是说,SRP Batcher通过两种手段加速渲染: 每个可渲染物体的材质数据持久化存在显存中。 专门定制的代码管理一个大的逐物体GPU Buffer,即图中的Per Object large buffer块。 SRP Batcher compatibility 在任何给定的场景中,有些可渲染物体与 SRP Batcher 兼容,有些则不兼容。即使使用不兼容的对象,Unity 也能正确渲染场景。这是因为兼容对象使用SRP Batcher代码路径,而其他对象使用标准的SRP 代码路径。能使用SRP Batcher 代码路径渲染的可渲染对象必须是以下的类型: 渲染对象必须是一个mesh或skinned mesh。它不能是粒子。 着色器必须与 SRP Batcher 兼容。HDRP 和 URP 中的所有光照和非光照着色器都符合此要求(这些着色器的粒子版本除外)。 可渲染对象不得使用 MaterialPropertyBlocks。 要使着色器与 SRP Batcher兼容,必须遵循以下几点:

URP Shader Pass Tag

原文地址 本节包含 URP 特定的 ShaderLab Pass 标签的描述。 URP Pass tags: LightMode 这个标签的值让渲染管线决定在执行渲染管线的不同部分时,使用哪个pass。如果您没有在一个pass中LightMode设置标签,URP 将使用给该pass使用SRPDefaultUnlit标签值。在 URP 中,LightMode标签有以下的几种: Property Description UniversalForward 本pass渲染可渲染的几何体并评估光源对光照效果的贡献。URP 在Forward Rendering路径中使用此标记值。 UniversalGBuffer 本pass渲染可渲染的几何体,但不计算光源对光照效果的贡献。URP 在Deferred Rendering路径中使用此标记值。 UniversalForwardOnly 本pass渲染对象几何体并评估光源对光照效果的贡献,类似于LightMode标签值为UniversalForward值时。与UniversalForward的不同之处在于,URP 可以将 这个pass用于Forward Rendering和Deferred Rendering路径。当 URP 使用Deferred Rendering路径时,且某个通道必须使用Forward Rendering路径渲染可渲染物体,请使用此值。例如,如果 URP 使用延迟渲染路径渲染场景。但场景中包含具有不适合使用GBuffer 的着色器数据的对象,(例如透明涂层法线(Clear Coat normals)),则使用此标记。如果着色器必须同时在Forward Rendering和Deferred Rendering路径中渲染,请使用UniversalForward和UniversalGBuffer标签值。如果着色器必须使用Forward Rendering路径进行渲染,而不管 URP 渲染器使用的什么渲染路径,请仅声明一个LightMode标记设置为的通道UniversalForwardOnly。 Universal2D 本pass渲染物体并评估 2D光源对光照效果的贡献。URP 在 2D 渲染器中使用此标记值。 ShadowCaster 本pass把光源视为摄像机,从光源的角度出发,把物体的深度值渲染到阴影贴图或深度纹理中。 DepthOnly 本pass把从实际摄像机的角度的透视体出发,把物体的深度值渲染到阴影贴图或深度纹理中。 Meta Unity 仅在 Unity Editor 中烘焙光照贴图时执行此 pass。Unity 会在构建 Player 时从着色器中剥离此 pass。 SRPDefaultUnlit 渲染对象时,使用此标记值绘制额外的通道。例如:绘制物体轮廓。此标记值对前向和延迟渲染路径均有效。当在pass中不显式指定LightMode的标志时,默认使用此标志 URP 不支持以下的内建管线所支持的 LightMode 标签:Always, ForwardAdd, PrepassBase, PrepassFinal, Vertex, VertexLMRGBM, VertexLM。

Pixel-Perfect Outline Shaders for Unity

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 原文地址 How outline shaders work 我第一次在电子游戏中看到3D物体的 轮廓线(outline) 是2003年育碧的《XIII》。这是我听说过的第一个具有 cel-shaded风格的 3D 游戏。(它基于一本图画小说。) 一旦我看到它,我必须知道它是如何完成的。《XIII》是一款使用虚幻2引擎的研发的游戏,我能够打开我信赖的 UnrealEd 并四处看看。 虚幻2引擎使用了固定功能的图形管道,这意味着XIII厚实的 墨水状轮廓(thick, ink-like outlines) 没有涉及着色器魔法。轮廓实际上是每个网格的一部分:外壳,悬停在角色的表面,具有倒置的面法线,因此只有内部可见,覆盖着黑色纹理。 自 2003 年和固定功能的图形管道以来,我们已经取得了长足的进步,但我们处理轮廓的方式几乎没有改变。最大的变化是轮廓不再需要成为网格的一部分;我们可以在单独的通道中使用顶点着色器来渲染网格的略微肥大的版本,并剔除正面(front face culled)。 换句话说,在我们的outline pass中,我们将取顶点的法线,乘以一个小数(我们不想增肥一个完整的单位!)得到一个偏移值,并将在变换顶点到裁剪空间之前,其此偏移值添加到顶点之前的位置。 这正是XIII在 2003 年在没有任何着色器的情况下完成的结果,但现在我们使用GPU自动地执行轮廓线绘制操作,来简化我们的创作工作流程。但我们可以做得更好。 Limitations of the classic technique 对于XIII受图形小说启发的美学而言,这些墨色轮廓恰到好处。但就像任何 15 年前的预着色技术一样,它们也有局限性,这使得它们作为通用轮廓解决方案的用处不大: 根据形状和视角,轮廓在对象表面上的厚度会有所不同。 当物体远离相机时,轮廓会被缩短(使用透视投影时) 轮廓宽度以对象空间单位指定,而不是以像素为单位。 请注意,这些是限制(limition),不一定是问题(problems)。在某些情况下,它们中的一些或全部可能是可取的。但他们每个人都应该在我们的控制之下。 我专注于技术,电脑艺术的。当我们作为艺术家以高水平的技术进行操作时,我们正在对我们制作的艺术——即我们代码的输出——施加精确的控制。 例如,我们可能希望将物体轮廓作为用户界面的一部分,以表明该物体已被选中。我们可能希望这些元素具有稳定的屏幕空间宽度。 或者我们可能正在模仿矢量或像素艺术风格,或者将 3D 网格与矢量或像素艺术精灵混合。我们需要能够以像素为单位匹配我们的轮廓宽度。 在本教程的过程中,我们将探索经典技术,然后对其进行改进,特别关注我们如何变换顶点位置,以更适应我们的需求,并为我们提供对最终外观的更多艺术控制。 Building the classic outline shader 下面是作为现代 Unity 着色器的经典XIII风格轮廓的代码。 Shader "Tutorial/Outline" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) _Glossiness ("Smoothness", Range(0, 1)) = 0.