Unity3D

一篇文章说透计算着色器的SV_DispatchThreadID

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com SV_DispatchThreadID 是HLSL(High-Level Shading Language)中的一个语义(Semantic),用于在Compute Shader中获取当前线程的全局线程ID。它是Compute Shader中非常重要的一个概念,用于确定每个线程处理的数据或任务。 SV_DispatchThreadID 的含义 全局线程ID: SV_DispatchThreadID 是一个 uint3 类型的变量,表示当前线程在全局线程空间中的ID。 它的三个分量(x、y、z)分别表示线程在X、Y、Z三个维度上的全局索引。 线程的全局位置: SV_DispatchThreadID 的值范围由程序语言层(例如C#) 的Dispatch 调用,和HLSL语言中的 numthreads 语句定义。 例如,如果调度了 Dispatch(10, 20, 30),并且 numthreads 是 [8, 8, 1],那么: SV_DispatchThreadID.x 的范围是 [0, 10*8-1](即 [0, 79])。 SV_DispatchThreadID.y 的范围是 [0, 20*8-1](即 [0, 159])。 SV_DispatchThreadID.z 的范围是 [0, 30*1-1](即 [0, 29])。 用途: SV_DispatchThreadID 通常用于确定当前线程处理的数据索引。 例如,在处理2D纹理时,SV_DispatchThreadID.xy 可以直接用作纹理坐标。 在处理1D数组时,SV_DispatchThreadID.x 可以直接用作数组索引。 SV_DispatchThreadID 的计算方式 SV_DispatchThreadID 的值是由以下两个因素决定的: 线程组的大小(由 numthreads 定义): 例如,[numthreads(8, 8, 1)] 表示每个线程组有 8x8x1 = 64 个线程。即是说,numthread语句,是声明“线程”的。 线程组的数量(由 Dispatch 调用定义):

使用mipmap streaming来优化GPU的纹理内存

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 本文所涉及到的API和Unity3D编辑器都是基于6000.0.25f1c1版本 1 mipmap streaming 简介 使用 mipmap 流来限制 GPU 内存中纹理的大小。 1.1 mipmap streaming的工作原理 对于每个被摄像机观察到的纹理,Unity会自动计算并加载其特定级别的mipmap,而不是加载所有级别。这意味着 Unity 只会将每个纹理的指定mipmap level的内容从磁盘传输到 CPU 和 GPU。 Unity 会以尽可能高的分辨率加载 mipmap level,但如果较高分辨率的 mipmap level不符合您设置的内存限制,则使用较低的 mipmap level。mipmap可预配置 Unity 在 GPU 上缓存指定mipmap level的纹理内容,以避免重复加载。 1.2 mipmap streaming的限制 Unity不支持对地形纹理使用mipmap streaming,因为 Unity 始终需要最高分辨率的 mipmap level。 Unity不支持对纹理数组、cubemap,3D纹理使用mipmap streaming。 如果使用Graphics.DrawMeshNow等 API来渲染纹理,Unity 将无法获得计算 mipmap level所需的信息。使用Texture2D.requestedMipmapLevel API 手动设置纹理的 mipmap level,或者禁用mipmap streaming。 如果纹理有tiling和offset属性,但又没指定使用_ST属性,Unity可能无法正确计算这种纹理的mipmap level。 2 启用 mipmap streaming 要启用 mipmap streaming,按照以下步骤操作: 点击【Edit|Project Settings】菜单项,弹出【Project Settings】面板,选中【Quality】项 在【Texture】部分中,启用【Mipmap Streaming】 在默认情况下,这时候为场景中的所有摄像机都打开了mipmap streaming。在编辑器中,mipmap streaming在edit mode或者play mode下都处于开启状态。

Unity3D的内置宏 DYNAMICLIGHTMAP_ON

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 在Unity中,DYNAMICLIGHTMAP_ON 是一个与 动态光照贴图(Dynamic Lightmaps) 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 控制着色器是否处理动态光照贴图数据,主要用于实现动态物体的间接光照混合效果。 核心含义 动态光照贴图标识 当该宏被激活时(#if defined(DYNAMICLIGHTMAP_ON)),表示当前渲染的物体 启用了动态光照贴图,需要在着色器中采样动态光照贴图数据。 若未激活,则物体仅使用静态光照贴图或实时光照。 技术目的 允许动态物体(如可移动的物件)与烘焙的静态场景光照进行间接光交互。 结合 Enlighten 或 Progressive Lightmapper 系统,实现动态物体的间接光实时更新。 触发条件 该宏在以下情况下自动激活: 物体设置 物体的 Mesh Renderer 组件中勾选 Lightmap Static 为 Contribute GI,同时设置 Lightmap Parameters 为支持动态更新。 光照系统配置 项目中启用了 Realtime Global Illumination(实时全局光照)。 使用 Baked Indirect 或 Shadowmask 混合光照模式。 Shader编译指令 在Shader中通过 #pragma multi_compile 或 #pragma shader_feature 声明动态光照贴图支持: #pragma multi_compile __ DYNAMICLIGHTMAP_ON 技术实现机制 1. 数据传递 动态光照贴图信息通过以下方式传递到着色器: 顶点数据:动态光照贴图坐标通过 TEXCOORD2 传递。 Uniform变量:动态光照贴图纹理(unity_DynamicLightmap)和采样器(samplerunity_DynamicLightmap)。 2. 着色器代码示例 struct v2f { float2 uv : TEXCOORD0; #if defined(LIGHTMAP_ON) float2 lightmapUV : TEXCOORD1; // 静态光照贴图UV #endif #if defined(DYNAMICLIGHTMAP_ON) float2 dynamicLightmapUV : TEXCOORD2; // 动态光照贴图UV #endif }; half3 GetLightmapColor(v2f i) { half3 staticGI = 0; half3 dynamicGI = 0; #if defined(LIGHTMAP_ON) staticGI = SampleLightmap(unity_Lightmap, samplerunity_Lightmap, i.

Unity3D的内置宏 REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 在Unity URP中,REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR 是一个与阴影计算相关的内置宏(Shader Variant Keyword),它的作用是: 核心含义 控制顶点着色器是否需要生成并传递阴影坐标插值器 当该宏被激活时,Unity会在顶点着色器阶段计算主光源的阴影坐标,并通过顶点着色器输出结构体(Varyings)传递到片元着色器。这使得片元着色器可以直接使用插值后的阴影坐标进行阴影采样,避免在片元阶段重复计算。 触发条件 该宏会自动激活,当以下条件满足时: 项目中启用了 主光源阴影(Main Light Shadows) 使用了 逐顶点阴影坐标插值 的优化模式(而非逐片元计算) 在Shader中通过 #pragma multi_compile 启用了阴影相关功能(例如 _MAIN_LIGHT_SHADOWS) 典型应用场景 在URP的Shader中,你会在顶点着色器输出结构体 Varyings 中看到类似代码: struct Varyings { float4 positionCS : SV_POSITION; float3 positionWS : TEXCOORD0; // 当 REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR 激活时,自动添加阴影坐标字段 #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR) float4 shadowCoord : TEXCOORD1; #endif }; 技术原理 阴影坐标生成 顶点着色器通过 GetShadowCoord(vertexInput) 计算阴影坐标,并存储在 shadowCoord 中。 插值优化 阴影坐标在顶点阶段计算后,通过插值器传递到片元着色器,减少片元阶段的计算量。 自动编译控制 Unity会根据项目设置和Shader特性,在编译时自动决定是否启用该宏,生成不同的Shader变体。 对比其他阴影模式 宏名称 计算阶段 性能消耗 精度 REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR 顶点着色器 较低 中等 REQUIRES_FRAGMENT_SHADOW_COORD_INTERPOLATOR 片元着色器 较高 较高 调试与手动控制 强制启用/禁用(不推荐)

Unity3D的内置宏 _LIGHT_LAYERS

Unity3D的内置宏 ADDITIONAL_LIGHTS_VERTEX 请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 在Unity URP/HDRP中,_LIGHT_LAYERS 是一个与 光源层级过滤(Light Layer Masking) 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 实现基于层级的光源与物体交互控制,允许开发者通过层掩码(Layer Masks)精确控制哪些光源可以影响特定物体。 核心含义 1. 功能定位 光源筛选机制:激活该宏后,物体会根据自身的 Light Layer Mask 和光源的 Light Layer Mask 进行匹配,只有匹配层的光源才会对该物体产生光照影响。 渲染优化:通过层级过滤减少无效光源计算,提升复杂场景性能。 2. 技术目标 精细化光源控制:例如让装饰性灯光只影响场景道具,不影响角色 多世界渲染支持:用于分屏游戏或VR中不同视角的独立光照逻辑 触发条件 该宏的激活需要同时满足以下条件: 项目设置启用 URP/HDRP Asset 中开启光源层支持: URP: Lighting > Light Layers > Enable Light Layers HDRP: Lighting > Light Layers Shader声明 在着色器中通过#pragma指令声明支持: #pragma multi_compile _ _LIGHT_LAYERS 光源与物体配置 光源的 Light Layer Mask 设置为非"Everything"值 物体的 Renderer组件 > Rendering Layer Mask 设置为与光源匹配的层级 技术实现机制 1.

Unity3D的内置宏 _ADDITIONAL_LIGHTS_VERTEX

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 在Unity URP中,_ADDITIONAL_LIGHTS_VERTEX 是一个与 附加光源处理方式 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 控制附加光源的光照计算阶段,决定是在 顶点着色器 还是 片元着色器 中处理附加光源的贡献。 核心含义 1. 光源计算阶段选择 启用时(_ADDITIONAL_LIGHTS_VERTEX 被定义): 附加光源的光照计算在 顶点着色器 阶段完成,计算结果通过顶点插值传递到片元着色器。 未启用时(默认或使用 _ADDITIONAL_LIGHTS): 附加光源的光照计算在 片元着色器 阶段逐像素完成。 2. 性能与质量的权衡 模式 性能消耗 光照精度 适用场景 _ADDITIONAL_LIGHTS_VERTEX 较低 中等(顶点插值) 移动端、低性能设备 _ADDITIONAL_LIGHTS 较高 高(逐像素) PC/主机、高质量渲染需求 触发条件 该宏的激活由以下因素决定: URP Asset设置 在URP资源中启用 Additional Lights(附加光源) 设置 Per Object Light 类型为 Vertex 或 Fragment(对应不同模式) Shader编译指令 在Shader中使用以下指令声明变体: #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS 实际光源数量 当场景中存在 附加光源(点光源、聚光灯等) 且影响当前渲染对象时,Unity自动选择对应变体。 技术实现原理 顶点着色器阶段处理(_ADDITIONAL_LIGHTS_VERTEX) // 顶点着色器中计算附加光源 Varyings vert(Attributes input) { Varyings output; // .

StylizedWater2插件帮助文档精读

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 插件官方文档地址 Stylized Water 2 入门指南 1. 准备工作 确保项目无控制台错误:未解决的代码错误会导致资源代码无法编译,材质可能显示为粉色。 项目设置: 使用 Universal Render Pipeline (URP):在 Edit -> Project Settings -> Graphics 中检查是否已分配 URP 资源。 如果没有正确设置 URP,材质将显示为粉色。请参考 Unity 的 URP 文档进行设置。 注意:建议在项目早期决定使用 URP,因为在生产过程中切换到 URP 可能导致其他自定义着色器失效。 颜色空间:推荐使用 Linear 颜色空间(新项目默认使用 Gamma 空间),详细信息请参考 Unity 文档。 2. URP 设置 启用必要选项: Depth Texture:用于多种效果(如深度和交互动画)。如果禁用,这些效果将失效,且在 Android 上构建时水可能会不可见。 Opaque Texture:用于折射效果,启用折射时需要。 如果这些选项未启用,但着色器使用了相关功能,材质 UI 中会显示警告并提供快速修复按钮。 相机设置:每个相机可以覆盖这些设置。如果某些效果在特定场景或相机中不可见,请检查这些选项是否被设置为“Off”。 质量级别设置:如果使用了不同质量级别的管道设置,请确保这些选项也已启用,否则在较低质量级别下运行时,水效果可能失效。 3. 向场景中添加水 建议:创建或复制材质(而不是直接使用包中的材质),以避免更新资源时设置被意外覆盖。 方法: 方法 1:将 Assets/StylizedWater2/Prefabs 中的预制件拖入场景,并调整材质属性。 方法 2:通过 GameObject -> 3D Object -> Water -> Object 菜单选项创建新的 Mesh Renderer。 方法 3: 在场景中创建一个平面网格。 创建新材质并分配 StylizedWater2/Default 着色器。 通过 Add Component -> Stylized Water 2 -> Water Object 添加 Water Object 组件(仅在需要使用平面反射时必要,但无负面影响)。 材质参数:每个参数都有工具提示,鼠标悬停可查看描述。 Stylized Water 2 着色器使用指南 1.

Unity3D中摄像机的FOV和Camera.ScreenToWorldPoint方法的关系

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 在Unity3D编程中经常会碰到以下的问题: 比如一开始的FOV为60度,后来设置为22度,可以通过怎样的公式,使得使用22度FOV对应生成的3D位置点,通过这个公式,可以转换到其位置点和使用60度生成的一样呢 当从一个FOV为60度的视角切换到22度的视角时,使用Camera.ScreenToWorldPoint函数生成的3D位置点会发生变化,因为FOV直接影响视锥体的宽度和高度。要解决这个问题,需要通过调整视锥体的缩放因子,来抵消FOV变化带来的位置偏移。 问题分析 当FOV变化时,屏幕坐标对应的世界坐标会随之缩放。假设有一个屏幕坐标screenPos,在FOV为60度时通过Camera.ScreenToWorldPoint生成一个3D位置点P60。当FOV变为22度时,假设生成的3D位置点为P22。我们需要找到一个转换公式,使得P22转换回P60。 FOV与世界坐标的关系 视锥体的高度(在深度为z处)与FOV通过以下公式相关: $$ Heightz=2×z×tan⁡(FOV2)\text{Height}_z = 2 \times z \times \tan\left(\frac{FOV}{2}\right)Heightz=2×z×tan(2FOV) $$ 其中: Height_z :在深度为z处的视锥体高度。 FOV:垂直视野角度。 z:深度(从摄像机到目标点的距离)。 视锥体的宽度和高度成比例地变化,具体公式为: $$ Widthz=Heightz×Aspect Ratio\text{Width}_z = \text{Height}_z \times \text{Aspect Ratio}Widthz=Heightz×Aspect Ratio $$ 对于两个不同的FOV(如60度和22度),可以计算出它们对应的视锥体高度比值。为了让FOV为22度时生成的世界坐标与FOV为60度时生成的一致,需要应用这个比值进行缩放。 缩放因子的推导 在FOV为60度时的视锥体高度: $$ \mathrm{Heigth}_{60}=2\times \mathrm{z}\times \tan \left( \frac{60^o}{2} \right) $$ 在FOV为22度时的视锥体高度: $$ \mathrm{Heigth}_{22}=2\times \mathrm{z}\times \tan \left( \frac{22^o}{2} \right) $$ 缩放因子: 需要将FOV为22度时的世界坐标缩放到FOV为60度的视锥体高度,因此缩放因子是这两个视锥体高度的比值: $$ ScaleFactor=\frac{Height_{60}}{Height_{22}}=\frac{\tan \left( 30^{o} \right)}{\tan \left( 11^{o} \right)} $$ 可以计算出这个缩放因子: $$ \mathrm{ScaleFactor}=\frac{0.5774}{0.1944}\approx 2.97 $$ 公式应用 在FOV为22度时生成的3D世界坐标P22可以通过如下公式转换为FOV为60度时的3D世界坐标P60:

Unity3D中根据深度值重建像素点对应的世界坐标

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 1 深度图介绍 就是将深度信息(Z坐标值)保存在了一张贴图上的R通道上,因为R通道的值范围是[0, 1],所以我们可以用ndc空间下的Z坐标值做下处理就能变成[0, 1]范围了( (Zndc+1)*0.5 2 C#接口取得深度图纹理的方法 Shader.GetGlobalTexture("_CameraDepthTexture") 3 在NDC空间下深度值的计算公式 4 从片元着色器中根据深度图反推出片元世界坐标且输出的shader Shader "zznewclear13/DepthToPositionShader" { Properties { [Toggle(REQUIRE_POSITION_VS)] _Require_Position_VS("Require Position VS", float) = 0 } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/core.hlsl" #pragma multi_compile _ REQUIRE_POSITION_VS sampler2D _CameraDepthTexture; struct Attributes { float4 positionOS : POSITION; float2 texcoord : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float2 texcoord : TEXCOORD0; }; Varyings Vert(Attributes input) { Varyings output = (Varyings)0; // 根据顶点在其模型坐标系下的值,计算得到在裁剪空间中的齐次坐标 VertexPositionInputs vertexPositionInputs = GetVertexPositionInputs(input.

不使用MeshRenderer去绘制Mesh【翻译】

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com 原文地址 在 Unity 中不使用 MeshRenderer 渲染网格 1. 概述 目的:使用 DrawMesh 系列方法在 Unity 中渲染大量网格,而无需创建和管理 GameObject。 特点: 网格会受到光照影响,可以投射和接收阴影。 可以针对所有相机或特定相机渲染。 支持 GPU 实例化和 Compute Shader。 2. 常用方法 DrawMesh:最简单的渲染方法,使用指定材质渲染网格。 DrawMeshInstanced:通过 GPU 实例化渲染大量相同网格,支持小规模变化(如颜色)。 DrawMeshInstancedIndirect:通过 ComputeBuffer 传递实例数量和位置等数据,适用于大规模实例化。 DrawMeshInstancedProcedural:与 DrawMeshInstancedIndirect 类似,但实例数量可以直接从 C# 传递。 DrawProcedural:在 GPU 上执行绘制调用,无需顶点或索引缓冲区,适用于 Compute Shader。 DrawProceduralIndirect:与 DrawProcedural 类似,但实例数量等数据从 ComputeBuffer 传递。 3. 代码示例 DrawMesh: public class ExampleDrawMesh : MonoBehaviour { public Mesh mesh; public Material material; void Update() { Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); } } DrawMeshNow: public class ExampleDrawMeshNow : MonoBehaviour { public Mesh mesh; public Material material; public void OnPostRender() { material.