Files
BlueRoseNote/03-UnrealEngine/卡通渲染相关资料/渲染功能/ARC/Rendering/屏幕对齐网格.md

132 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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作为屏幕坐标输入
- 参考分辨率为 1280x720offset 以像素为单位
- 深度设为接近远裁面(`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` 材质访问函数 |