--- title: 屏幕对齐网格 date: 2026-05-03 00:00:00 excerpt: 将网格直接渲染到屏幕空间,用于 UI/HUD 叠加元素 tags: - ARC - Rendering - VertexFactory rating: ⭐ --- # 屏幕对齐网格 返回 [[Rendering]] ## 概述 屏幕对齐网格(ScreenAlignedMesh)将 3D 网格直接投影到屏幕空间坐标系中渲染,用于实现 UI 元素、HUD 叠加或其他需要固定屏幕位置的网格效果。 ## 实现 在所有顶点着色器中通过 `USES_SCREEN_ALIGNED_MESH` 宏启用: ```hlsl #if USES_SCREEN_ALIGNED_MESH { float2 p = Input.Position.xz * flip; float3 offset = GetMaterialScreenAlignedMeshOffset(VertexParameters); float3 scale = GetMaterialScreenAlignedMeshScale(VertexParameters); // 基于 1280x720 的参考分辨率 float2 ScreenPos = p.xy * scale.xy; ScreenPos.x += offset.x / 640.0f; ScreenPos.y += -offset.y / 360.0f; ScreenPos.xy += GetMaterialWorldPositionOffset(VertexParameters).xy; const float z = 1.0f - 0.00001f; // 接近远裁面 WorldPosition = 0; Output.Position = float4(ScreenPos, z, 1); } #endif ``` 关键点: - 使用 `Input.Position.xz`(不是 xy)作为屏幕坐标输入 - 参考分辨率为 1280x720,offset 以像素为单位 - 深度设为接近远裁面(`1.0 - 0.00001`),确保不遮挡 3D 场景 - 跳过雾效计算(`TRANSLUCENCY_NEEDS_BASEPASS_FOGGING` 对 ScreenAlignedMesh 禁用) ## 材质控制 通过 [[自定义材质属性]] 中的两个属性控制: - `MP_ScreenAlignedMeshOffset` — 屏幕偏移(像素,基于 1280x720) - `MP_ScreenAlignedMeshScale` — 缩放系数 材质标记 `bScreenAlignedMesh` 启用此模式。 ## 完整代码解析 ### BasePassVertexShader.usf — 屏幕对齐变换 ```hlsl // ASW Change : 2016/05/16 13:56:33 Takuro.K // 屏幕对齐网格:将3D网格直接投影到屏幕空间 #if USES_SCREEN_ALIGNED_MESH { // 获取 LocalToWorld 矩阵(区分实例化和非实例化模式) #if PARTICLE_MESH_INSTANCED float4x4 LocalToWorld = VertexParameters.InstanceLocalToWorld; #else float3x3 LocalToWorld = GetLocalToWorld3x3(VertexParameters.PrimitiveId); #endif // 从 LocalToWorld 矩阵的对角元素获取翻转方向 // 这样网格在镜像 Transform 下仍然正确显示 #if PARTICLE_MESH_INSTANCED float2 flip = sign( float2( Input.Transform1.x, LocalToWorld[1][1] ) ); #else float2 flip = sign( float2( LocalToWorld[0][0], LocalToWorld[1][1] ) ); #endif // 使用顶点的 X 和 Z 坐标作为屏幕坐标(不是 XY!) // 这是因为网格在 DCC 中通常面向 Z 轴建模 float2 p = Input.Position.xz * flip; // 从材质图获取偏移和缩放参数 float3 offset = GetMaterialScreenAlignedMeshOffset(VertexParameters); float3 scale = GetMaterialScreenAlignedMeshScale(VertexParameters); // 基于 1280x720 参考分辨率计算屏幕坐标 // NDC 范围 [-1, 1],所以 /640 和 /360 将像素单位转为 NDC float2 ScreenPos = p.xy * scale.xy; ScreenPos.x += offset.x / 640.0f; // X 偏移(向右为正) ScreenPos.y += -offset.y / 360.0f; // Y 偏移(向上为正,NDC Y 轴反转) // WorldPositionOffset 也可以叠加微调 ScreenPos.xy += GetMaterialWorldPositionOffset(VertexParameters).xy; // 深度设为接近远裁面,确保不遮挡 3D 场景 const float z = 1.0f - 0.00001f; // 清零世界坐标(屏幕空间渲染不需要) WorldPosition = 0; // 直接设置裁剪空间输出(w=1 表示无透视除法) Output.Position = float4( ScreenPos, z, 1 ); } #endif ``` ### BasePassCommon.ush — 禁用雾效 ```hlsl // ASW Change : 2017/01/30 18:00:41 Takuro.K // 屏幕对齐网格不需要雾效(它们是屏幕空间元素) #define TRANSLUCENCY_NEEDS_BASEPASS_FOGGING ( MATERIAL_ENABLE_TRANSLUCENCY_FOGGING && MATERIALBLENDING_ANY_TRANSLUCENT && !MATERIAL_USES_SCENE_COLOR_COPY && !USES_SCREEN_ALIGNED_MESH) // <-- 新增条件 ``` ## 代码修改情况 | 文件路径 | 行号 | 修改类型 | 修改内容 | |---------|------|---------|---------| | `Shaders/Private/BasePassVertexShader.usf` | L118~L155 | 新增 | 屏幕对齐网格变换逻辑(1280x720基准/深度设置/WorldPosition清零) | | `Shaders/Private/BasePassCommon.ush` | L28~L34 | 修改 | `TRANSLUCENCY_NEEDS_BASEPASS_FOGGING` 禁用 ScreenAlignedMesh 雾效 | | `Shaders/Private/DepthOnlyVertexShader.usf` | — | 新增 | 同上变换逻辑(DepthOnly Pass) | | `Shaders/Private/HitProxyVertexShader.usf` | — | 新增 | 同上(HitProxy Pass) | | `Shaders/Private/DebugViewModeVertexShader.usf` | — | 新增 | 同上(DebugViewMode Pass) | | `Shaders/Private/MaterialTemplate.ush` | L2243~L2252 | 新增 | `GetMaterialScreenAlignedMeshOffset/Scale` 材质访问函数 |