137 lines
4.1 KiB
Markdown
137 lines
4.1 KiB
Markdown
|
|
---
|
|||
|
|
title: 正交投影混合
|
|||
|
|
date: 2026-05-03 00:00:00
|
|||
|
|
excerpt: OrthoBlend 透视校正技术,实现动画风格的透视扁平化效果
|
|||
|
|
tags:
|
|||
|
|
- ARC
|
|||
|
|
- Rendering
|
|||
|
|
- VertexFactory
|
|||
|
|
- Toon
|
|||
|
|
rating: ⭐
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 正交投影混合
|
|||
|
|
|
|||
|
|
返回 [[Rendering]]
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
正交投影混合(OrthoBlend)是 ARC 引擎实现**动画风格透视扁平化**的核心技术。在动画/格斗游戏中,角色需要减少透视畸变以保持美术控制的外观,这通过在透视投影和正交投影之间进行混合来实现。
|
|||
|
|
|
|||
|
|
引擎提供了两个版本:
|
|||
|
|
- **V1** (`USES_ORTHO_BLEND_POSITION`):简单的 X 轴正交混合
|
|||
|
|
- **V2** (`USES_ORTHO_BLEND_POSITION2`):基于物体中心距离的全透视校正("Purse correction")
|
|||
|
|
|
|||
|
|
## 实现细节
|
|||
|
|
|
|||
|
|
### V1:X 轴正交混合
|
|||
|
|
|
|||
|
|
在 `Common.ush` 中定义:
|
|||
|
|
|
|||
|
|
```hlsl
|
|||
|
|
float4 GetOrthoBlendPosition(
|
|||
|
|
float4 WorldPosition,
|
|||
|
|
float4x4 ViewProjectionMatrix,
|
|||
|
|
float weight)
|
|||
|
|
{
|
|||
|
|
float4 ScreenPosition = mul(WorldPosition, ViewProjectionMatrix);
|
|||
|
|
|
|||
|
|
// 计算正交投影的 X 坐标
|
|||
|
|
float OrthoScreenPositionX = dot(
|
|||
|
|
ResolvedView.OrthoViewProjectionX, WorldPosition);
|
|||
|
|
|
|||
|
|
// 在透视和正交之间混合 X 轴
|
|||
|
|
ScreenPosition.x = lerp(
|
|||
|
|
ScreenPosition.x,
|
|||
|
|
OrthoScreenPositionX * ScreenPosition.w,
|
|||
|
|
weight * ResolvedView.OrthoBlendParameter);
|
|||
|
|
|
|||
|
|
return ScreenPosition;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`OrthoBlendParameter` 从 C++ 端通过 `ViewUniformShaderParameters` 传入,全局控制混合强度。`weight` 来自材质属性 `MP_OrthoBlendWeight`,允许逐材质控制。
|
|||
|
|
|
|||
|
|
### V2:全透视校正
|
|||
|
|
|
|||
|
|
```hlsl
|
|||
|
|
float4 GetOrthoBlendPosition2(
|
|||
|
|
float4 WorldPosition,
|
|||
|
|
float4x4 ViewProjectionMatrix,
|
|||
|
|
float weight,
|
|||
|
|
float3 ObjWorldPosition)
|
|||
|
|
{
|
|||
|
|
// 计算顶点相对于物体中心的偏移
|
|||
|
|
float3 offset = WorldPosition.xyz - ObjWorldPosition.xyz;
|
|||
|
|
|
|||
|
|
// 物体中心到相机的距离(沿视线方向)
|
|||
|
|
float dist = abs(dot(
|
|||
|
|
ObjWorldPosition.xyz - ResolvedView.WorldCameraOrigin.xyz,
|
|||
|
|
ResolvedView.ViewForward.xyz));
|
|||
|
|
|
|||
|
|
// 将顶点"拍平"到与物体中心相同距离的平面
|
|||
|
|
float3 origin = ResolvedView.WorldCameraOrigin.xyz
|
|||
|
|
+ ResolvedView.ViewForward.xyz * dist;
|
|||
|
|
WorldPosition.xy = origin.xy + offset.xy;
|
|||
|
|
|
|||
|
|
// ... 后续投影变换
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
V2 的原理:将所有顶点投影到与物体中心等距的平面上,消除了前后肢体因透视导致的大小差异。
|
|||
|
|
|
|||
|
|
### 全 VertexFactory 覆盖
|
|||
|
|
|
|||
|
|
两个版本均在所有顶点着色器中实现:
|
|||
|
|
|
|||
|
|
| 顶点着色器 | 文件 |
|
|||
|
|
|-----------|------|
|
|||
|
|
| BasePass | `BasePassVertexShader.usf` |
|
|||
|
|
| DepthOnly | `DepthOnlyVertexShader.usf` |
|
|||
|
|
| PositionOnlyDepth | `PositionOnlyDepthVertexShader.usf` |
|
|||
|
|
| HitProxy | `HitProxyVertexShader.usf` |
|
|||
|
|
| DebugViewMode | `DebugViewModeVertexShader.usf` |
|
|||
|
|
|
|||
|
|
覆盖的 VertexFactory:
|
|||
|
|
- `LocalVertexFactory.ush`
|
|||
|
|
- `GpuSkinVertexFactory.ush`
|
|||
|
|
- `LandscapeVertexFactory.ush`
|
|||
|
|
- `MeshParticleVertexFactory.ush`
|
|||
|
|
- 所有 Particle VertexFactory
|
|||
|
|
|
|||
|
|
## 材质属性
|
|||
|
|
|
|||
|
|
通过 `MP_OrthoBlendWeight` 材质属性控制每个材质的混合权重:
|
|||
|
|
|
|||
|
|
```cpp
|
|||
|
|
// MaterialTemplate.ush
|
|||
|
|
float GetMaterialOrthoBlendWeight(FMaterialVertexParameters Parameters)
|
|||
|
|
{
|
|||
|
|
%s; // 由材质图生成
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## C++ 端支持
|
|||
|
|
|
|||
|
|
- `SceneRendering.cpp`:计算 `OrthoBlendParameter` 并写入 ViewUniformBuffer
|
|||
|
|
- `SceneTypes.h`:`MP_OrthoBlendWeight` 枚举值
|
|||
|
|
- `HLSLMaterialTranslator.cpp`:材质编译支持
|
|||
|
|
|
|||
|
|
## 关联文档
|
|||
|
|
|
|||
|
|
- [[自定义材质属性]] — `MP_OrthoBlendWeight` 的定义
|
|||
|
|
- [[屏幕对齐网格]] — 另一种屏幕空间变换方案
|
|||
|
|
- [[局部位置缩放]] — 局部空间的顶点变换
|
|||
|
|
|
|||
|
|
## 修改文件列表
|
|||
|
|
|
|||
|
|
| 文件 | 修改类型 |
|
|||
|
|
|------|---------|
|
|||
|
|
| `Shaders/Private/Common.ush` | 新增 `GetOrthoBlendPosition` / `GetOrthoBlendPosition2` |
|
|||
|
|
| `Shaders/Private/BasePassVertexShader.usf` | 调用正交混合 |
|
|||
|
|
| `Shaders/Private/DepthOnlyVertexShader.usf` | 调用正交混合 |
|
|||
|
|
| `Shaders/Private/PositionOnlyDepthVertexShader.usf` | 调用正交混合 |
|
|||
|
|
| `Shaders/Private/HitProxyVertexShader.usf` | 调用正交混合 |
|
|||
|
|
| `Shaders/Private/DebugViewModeVertexShader.usf` | 调用正交混合 |
|
|||
|
|
| 所有 VertexFactory `.ush` | 提供 ObjWorldPosition |
|