--- 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 |