Posts

彻底弄懂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选项可以指定,如下图所示:

在HLSL中对浮点数和整数之间进行转换

以下是逐行注释和详细说明的Unity Shader代码分析: 1. 打包整数函数 PackInt float PackInt(uint i, uint numBits) // 打包整数 { uint maxInt = (1u << numBits) - 1u; // 计算最大整数值 return saturate(i * rcp(maxInt)); // 将整数归一化到[0, 1]范围 } 功能说明 该函数将一个无符号整数 i 打包为一个浮点数,范围在 [0, 1] 之间。 通过将整数 i 除以最大整数值 maxInt,将其归一化到 [0, 1] 范围。 参数说明 i:需要打包的无符号整数。 numBits:整数的位数,用于计算最大整数值。 关键点 1u << numBits:通过左移操作计算 2^numBits,即最大整数值加1。 maxInt = (1u << numBits) - 1u:计算最大整数值。例如,numBits = 8 时,maxInt = 255。 rcp(maxInt):计算 1.0 / maxInt,用于归一化。 saturate:将结果限制在 [0, 1] 范围内,防止溢出。 示例 输入:i = 128, numBits = 8 计算: maxInt = (1u << 8) - 1u = 255 rcp(maxInt) = 1.

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 标签参考 1. LightMode 标签 标签值 描述 适用场景 UniversalForward 渲染对象几何体并计算所有光照贡献。 Forward 渲染路径 UniversalGBuffer 渲染对象几何体但不计算光照贡献。 Deferred 渲染路径 UniversalForwardOnly 渲染对象几何体并计算所有光照贡献,可在 Forward 和 Deferred 渲染路径中使用。 Deferred 渲染路径中需要 Forward 渲染的对象(如 Clear Coat 法线) DepthNormalsOnly 用于深度和法线预渲染,生成环境光遮蔽(AO)。 Deferred 渲染路径,结合 UniversalForwardOnly 使用 Universal2D 渲染对象并计算 2D 光照贡献。 2D 渲染器 ShadowCaster 渲染对象从光源视角的深度到阴影贴图或深度纹理。 阴影生成 DepthOnly 渲染从相机视角的深度信息到深度纹理。 深度渲染 Meta 仅在 Unity 编辑器烘焙光照贴图时执行,构建时会被剥离。 光照贴图烘焙 SRPDefaultUnlit 用于绘制额外 Pass(如对象轮廓),适用于 Forward 和 Deferred 渲染路径。 绘制额外 Pass(如轮廓) MotionVectors 用于支持运动矢量(Motion Vectors)的 Pass。 运动矢量渲染 2.