Unity3D

彻底弄懂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 标签参考 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.

Pixel-Perfect Outline Shaders for Unity

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 原文地址 以下是基于你提供的内容的总结和解读,保留示例代码和图片链接: 轮廓着色器的工作原理与优化 1. 经典轮廓技术 起源:在 2003 年游戏《XIII》中首次看到 3D 对象的轮廓效果,使用固定功能管线实现。 实现方式:通过网格的外壳(Outer Hull)和反转法线绘制轮廓,覆盖黑色纹理。 现代改进:使用顶点着色器在单独 Pass 中渲染略微膨胀的网格,剔除正面。 2. 经典轮廓技术的局限性 局限性 描述 轮廓宽度不均匀 轮廓宽度随物体形状和视角变化。 透视缩短 轮廓宽度随物体远离相机而变窄(透视投影)。 对象空间单位 轮廓宽度以对象空间单位指定,而非像素。 3. 经典轮廓着色器代码 Shader "Tutorial/Outline" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) _Glossiness ("Smoothness", Range(0, 1)) = 0.5 _Metallic ("Metallic", Range(0, 1)) = 0 _OutlineColor ("Outline Color", Color) = (0, 0, 0, 1) _OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.03 } Subshader { Tags { "RenderType" = "Opaque" } CGPROGRAM #pragma surface surf Standard fullforwardshadows Input { float4 color : COLOR; } half4 _Color; half _Glossiness; half _Metallic; void surf(Input IN, inout SufaceStandardOutput o) { o.

使用Android NDK编译xlua

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 基本上就是按照参考网页所示的那样子,先后安装好Android Studio,打开【File|Setting】菜单项打开界面,把google的CMake选好。注意这里一定要用google家的CMake,用原生CMake不行 如果google CMake的版本过高的话,会报CMake Error: Could not create named generator Android Gradle - Ninja的错误,较新版本的google CMake会产生这个问题,反而低版本的不会,所以选用3.6.4111459版本的才行。Stack Overflow网站上有人就这个问题做了回答: Compatibility of CMake version might be an issue, Old NDK (below 13b) is not compatible with the new CMake, so, either update NDK or remove the new CMake (to force older CMake usage). Check your System Setting and version listed under SDK Tools Go to Appearance & Behaviour -> System Settings -> Android SDK Incompatible 3.

Unity3D的SRP,Static Batching、Dynamic Batching和GPU instancing

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 所谓的draw call batching(绘制批处理),就是指对将要绘制的N个网格,在保持渲染结果正确的前提下,将draw call进行合并,以一整批,而不是单个的方式,向GPU提交这些draw call操作。 绘制批处理有若干种实现方式,有些方式只是减少了提交draw call的次数,但执行draw call的次数没变少。有些方式则是直接减少了draw call的数量。 在《Unity DrawCall、Batch、SetPassCall的区别》一文中对Batching的解释很到位,摘录如下: Batch 把数据加载到显存,设置渲染状态,CPU调用GPU渲染的过程称之为一个Batch。这其实就是渲染流程的运用阶段,最终输出一个渲染图元(点、线、面等),再传递给GPU进行几何阶段和光栅化阶段的渲染显示。一个Batch必然会触发一次或多次DrawCall,且包含了该对象的所有的网格和顶点数据以及材质信息。把数据加载到显存是指把渲染所需的数据从硬盘加载到内存(RAM),再将网格和纹理等加载到显卡(VRAM),这一步比较耗时。设置渲染状态就是设置场景中的网格的顶点(Vertex)/片元(Fragment)着色器,光源属性,材质等。Unity提供的动态合批(Dynamic Batching )合并的就是这一过程,将渲染状态相同的对象合并成一个Batch,减少DrawCall。 还有对SetPassCall的解释也很好,摘录如下: SetPassCall Shader脚本中一个Pass语义块就是一个完整的渲染流程,一个着色器可以包含多个Pass语义块,每当GPU运行一个Pass之前,就会产生一个SetPassCall,所以可以理解为一次完整的渲染流程次数。 由此可见,一个Batch包含一个或多个DrawCall,都是产生是在CPU阶段,而目前普遍渲染的瓶颈恰恰就是CPU,GPU的处理速度比CPU快多了,Draw Call太高,CPU会把大量时间花费在处理Draw Call调用上。如果Batch太大,CPU需要频繁的从硬盘加载数据,切换渲染状态,这个消耗要比DrawCall大,所以后面Unity才逐渐弱化了DrawCall的显示。 再提一下,优化的时候还要关注下Statistics窗口上的三角形数(Tris)和顶点数(Verts),这两个数据也是会影响到性能,比如单个物体的顶点数最好不要超过900,不然会影响到Unity的动态合批。Unity的Statistics窗口上的三角形数(Tris)和顶点数(Verts)并不仅仅是视锥中的梯形内的三角形数和顶点数,而是Camera中 field of view所有取值下的三角形数和顶点数。也就是说,即使当前Game视图中看不到这个 cube,只有 field of view在1-179 范围内都看不到这个cube,stats面板才不会统计,GPU才不会渲染,否则都会渲染,而且Unity不会把模型拆分,这个模型哪怕只有1个顶点需要渲染,Unity也会把整个模型都渲出来。 四种优化方式的适用场合 优化方式的优先级 一些细节笔记 参考网页 Unity DrawCall、Batch、SetPassCall的区别 浅谈Draw Call和Batch的区别 Unity渲染优化的4种批处理:静态批处理,动态批处理,SRP Batcher 与 GPU Instancing Draw call batching 为什么baches(draw calls)数那么高? 它们有什么意义? 请教Unity中的Draw Call Batch规则