Bevy 渲染管线迁移指南:八面体编码 shader 工具函数从bevy_pbr迁移到bevy_render
【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy
本文基于 Bevy 迁移指南 shader_octahedral_moved.md,讲解 shader(WGSL)层面的八面体(octahedral)法线编码/解码工具函数octahedral_encode、octahedral_decode、octahedral_decode_signed如何从bevy_pbr::utils迁移到bevy_render::utils:为什么这些函数被下沉到更底层的 crate、新位置下完整的函数清单与实现细节,以及自定义 shader 需要修改哪些#import语句。读完本篇,你可以正确处理升级 Bevy 后自定义着色器中因 import 路径变化导致的编译失败,并理解八面体编码在 Bevy 顶点压缩、meshlet 几何压缩与全局光照采样中的实际用途。
变更内容:shader 工具函数的新 import 路径
迁移指南给出的变更非常直接:三个八面体编码 shader 函数从bevy_pbr::utils命名空间移到了bevy_render::utils命名空间。升级前与升级后的写法对比如下:
// BEFORE #import bevy_pbr::utils::{octahedral_encode, octahedral_decode, octahedral_decode_signed} // AFTER #import bevy_render::utils::{octahedral_encode, octahedral_decode, octahedral_decode_signed}这意味着:如果你在项目或第三方插件的自定义 shader 中通过#import引入了这三个函数,只需把bevy_pbr::utils替换为bevy_render::utils,函数名与签名均保持不变,无需改动任何函数调用逻辑。
从源码结构看,这次迁移的动机是合理且清晰的:八面体编码本质上是一种通用的向量压缩/解压数学工具,而非 PBR 光照计算的一部分。当前仓库中该实现位于 crates/bevy_render/src/utils.wesl,并且调用方横跨多个 crate——除了bevy_pbr之外,bevy_solari(实时 GI)与bevy_dev_tools(调试叠加层)的 shader 也都引用它。把它放在依赖层级更低的bevy_render中,可以让所有渲染相关 crate 共享同一份实现,而不必让bevy_solari等 crate 仅仅为了一个数学函数去依赖bevy_pbr。
新位置:bevy_render::utils中完整可用的函数清单
迁移后的utils模块(由 crates/bevy_render/src/utils.wesl 定义)实际暴露的函数比迁移指南提到的三个更多,它同时服务于顶点属性压缩场景。仓库中该文件的完整函数为:
| 函数 | 输入/输出 | 用途 |
|---|---|---|
octahedral_encode(v: vec3<f32>) -> vec2<f32> | 单位向量 → [0, 1] 区间八面体坐标 | 编码法线或单位方向向量,结果可直接映射到 Unorm 格式 |
octahedral_decode(v: vec2<f32>) -> vec3<f32> | [0, 1] 区间坐标 → 单位向量 | 解码上一步的结果 |
octahedral_decode_signed(v: vec2<f32>) -> vec3<f32> | [-1, 1] 区间坐标 → 单位向量 | 解码 Snorm 格式存储的八面体坐标 |
octahedral_decode_tangent(v: vec2<f32>) -> vec4<f32> | 带符号编码坐标 → 切线+符号 | 解码切线向量,w 分量为符号位 |
decompress_vertex_normal(compressed_normal: vec2<f32>) -> vec3<f32> | 压缩法线 → 法线 | 内部即调用octahedral_decode_signed |
decompress_vertex_tangent(compressed_tangent: vec2<f32>) -> vec4<f32> | 压缩切线 → 切线+符号 | 内部即调用octahedral_decode_tangent |
decompress_vertex_position(compressed_position: vec4<f32>, aabb_center, aabb_half_extents) -> vec3<f32> | 压缩位置 + AABB 参数 → 世界位置 | 位置反量化 |
decompress_vertex_uv(compressed_uv: vec2<f32>, uv_min_and_extents: vec4<f32>) -> vec2<f32> | 压缩 UV + 范围参数 → UV | UV 反量化 |
以octahedral_encode的实现为例(crates/bevy_render/src/utils.wesl):
// https://jcgt.org/published/0003/02/01/paper.pdf // For encoding normals or unit direction vectors as octahedral coordinates. fn octahedral_encode(v: vec3<f32>) -> vec2<f32> { var n = v / (abs(v.x) + abs(v.y) + abs(v.z)); let octahedral_wrap = (1.0 - abs(n.yx)) * select(vec2(-1.0), vec2(1.0), n.xy > vec2f(0.0)); let n_xy = select(octahedral_wrap, n.xy, n.z >= 0.0); return n_xy * 0.5 + 0.5; } // For decoding normals or unit direction vectors from octahedral coordinates. fn octahedral_decode(v: vec2<f32>) -> vec3<f32> { let f = v * 2.0 - 1.0; return octahedral_decode_signed(f); } // For decoding normals or unit direction vectors from octahedral coordinates. Input is [-1, 1]. fn octahedral_decode_signed(v: vec2<f32>) -> vec3<f32> { var n = vec3(v.xy, 1.0 - abs(v.x) - abs(v.y)); let t = saturate(-n.z); let w = select(vec2(t), vec2(-t), n.xy >= vec2(0.0)); n = vec3(n.xy + w, n.z); return normalize(n); }实现注释中引用的 JCGT 论文(Fast, Accurate, and Robust Normal Encoding Using Octahedral Vectors and the Sign Bit)说明了算法来源:先除以|x| + |y| + |z|把向量投影到八面体上,正八面体(z ≥ 0)与负八面体(z < 0,octahedral_wrap折返)分别用不同映射,最后* 0.5 + 0.5把结果平移到 [0, 1] 区间,方便以 16 位无符号/有符号整数格式存储。octahedral_decode_signed则是其严格逆过程,输入约定为 [-1, 1] 区间(即 Snorm 反量化后的值)。
迁移后的仓库内调用现状
在当前仓库中,所有引用方均已经使用新路径bevy_render::utils,可以作为迁移写法的参照示例:
- crates/bevy_pbr/src/meshlet/bindings.wesl:
import bevy_render::utils::octahedral_decode_signed;(meshlet 压缩顶点解码) - crates/bevy_pbr/src/deferred/functions.wesl:
import bevy_render::utils::{octahedral_encode, octahedral_decode};(延迟渲染 GBuffer 读写) - crates/bevy_solari/src/realtime/restir.wesl、crates/bevy_solari/src/realtime/gbuffer_utils.wesl、crates/bevy_solari/src/realtime/initial_path.wesl、crates/bevy_solari/src/realtime/presample_light_tiles.wesl、crates/bevy_solari/src/realtime/resolve_dlss_rr_textures.wesl:实时 GI 管线中编码/解码光源方向与采样方向
- crates/bevy_dev_tools/src/debug_overlay.wesl:调试叠加层解码压缩法线
如果你的自定义 shader 之前写的是#import bevy_pbr::utils::...,对照上述任一文件的 import 行即可确认目标写法;单函数与{...}多函数两种形式均支持。
底层原理与 Rust 侧的对应实现
理解这次迁移,绕不开八面体编码在 Bevy 中的两大应用场景。
场景一:mesh 顶点属性压缩。bevy_mesh提供了 CPU 侧的 Rust 实现,位于 crates/bevy_mesh/src/vertex.rs,包括octahedral_encode_signed(输出 [-1, 1] 区间)、octahedral_encode_tangent、octahedral_decode_signed与octahedral_decode_tangent。当 mesh 开启属性压缩时(MeshAttributeCompressionFlags,见 crates/bevy_mesh/src/mesh.rs 中关于 Snorm16x2 法线的说明),法线与切线从Float32x3/Float32x4转换为由八面体编码后的Snorm16x2——每顶点法线从 12 字节降到 4 字节。GPU 侧解码时正好调用decompress_vertex_normal/decompress_vertex_tangent(即octahedral_decode_signed/octahedral_decode_tangent)。同文件中还有octahedral_encode_decode单元测试,验证了编码/解码在含符号位切线在内的多种边界向量上的往返精度。
场景二:meshlet 几何压缩。crates/bevy_pbr/src/meshlet/from_mesh.rs 在构建 meshlet 数据时对法线执行pack2x16snorm(octahedral_encode(normal)),即以 16 位有符号归一化整数打包两个分量上传 GPU,shader 端再用octahedral_decode_signed恢复。
shader 侧与 Rust 侧的一个细节差异值得注意:crates/bevy_render/src/utils.wesl 中octahedral_encode的返回值经过* 0.5 + 0.5平移,落在 [0, 1] 区间,因此配套解码用octahedral_decode;而 Rust 侧octahedral_encode_signed保持 [-1, 1] 区间,配套解码用octahedral_decode_signed。两者是同一算法在不同数值区间约定下的变体,选择哪一对取决于你的数据存储格式(Unorm 还是 Snorm)。
实操迁移步骤
对自定义 shader 用户而言,迁移只需一步:
- 打开所有自定义
.wesl/ shader 文件,全局替换bevy_pbr::utils为bevy_render::utils(仅限这三个八面体函数所在的 import 语句;如果你的 import 里还有其它函数,需按函数实际所在的模块拆分语句)。 - 确认函数调用处无需改动——函数名与签名在迁移前后保持一致。
- 重新运行应用,shader 编译期即可验证 import 路径是否生效。
需要注意的前提:该 import 语法基于 Bevy 当前使用的.weslshader 格式;迁移指南对应 PR 编号为 21926,适用于升级到包含该 PR 的 Bevy 版本之后。如果你的代码同时依赖旧的bevy_pbr::utils中其它(非八面体)符号,请逐个核对每个符号在新版本中的实际位置,而不是整段机械替换。
小结
- 本次迁移只改变了 shader 工具函数的命名空间位置:
bevy_pbr::utils::{octahedral_encode, octahedral_decode, octahedral_decode_signed}→bevy_render::utils::{...},API 完全兼容。 - 新位置 crates/bevy_render/src/utils.wesl 还额外提供
octahedral_decode_tangent、decompress_vertex_normal/tangent/position/uv等与顶点压缩相关的函数,可一并按需引入。 - 算法实现与 crates/bevy_mesh/src/vertex.rs 中的 Rust 侧编码/解码互为 CPU/GPU 配对,理解这对关系有助于在自定义资产管线上复用 Bevy 的八面体压缩格式。
【免费下载链接】bevyA refreshingly simple>项目地址: https://gitcode.com/GitHub_Trending/be/bevy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考