
Bevy 著色器遷移到 WESL從 naga_oil 預處理到原生著色器模塊【免費下載鏈接】bevyA refreshingly simple>項目地址: https://gitcode.com/GitHub_Trending/be/bevyBevy 的著色器已從 naga_oil 預處理器方言全面切換到 WESL完整覆蓋新舊語法對照、模塊命名規(guī)則、著色器定義shader defs的映射方式并結合 bevy_shader 源碼 與 著色器緩存實現(xiàn) 講解 WESL 在 Bevy 中的編譯、解析與緩存機制幫助你安全完成自定義著色器的遷移。核心變化WESL 取代 naga_oilBevy 引擎內置的所有著色器現(xiàn)在都直接用 WESL 編寫naga_oil預處理器被徹底移除。遷移指南給出的結論是使用 naga_oil 方言的自定義著色器必須翻譯成 WESL并將擴展名從.wgsl改為.wesl不含任何預處理指令的純 WGSL 文件可以繼續(xù)原樣使用無需改動。這一判斷的依據可以在加載器源碼中得到印證ShaderLoader 按擴展名分派到三種Source變體——spv走Shader::from_spirv、wgsl走Shader::from_wgsl、wesl走Shader::from_wesl三者分別對應 Source 枚舉 中的SpirV、Wgsl、Wesl。也就是說純 WGSL 文件進入緩存后會被原樣交給渲染器編譯完全繞開 WESL 管線。同時有兩條加載規(guī)則值得注意shader.rs L288-L293只有.wesl文件支持 shader defs。如果給.wgsl/.spv著色器附加了shader_defsBevy 會打印警告 “Tried to load a non-wesl shader with shader defs, this isnt supported” 并忽略這些定義不支持的擴展名會直接 panicunhandled extension加載器聲明的合法擴展名為[spv, wgsl, wesl]。語法對照BEFORE / AFTER 逐行解析遷移指南給出的新舊對照示例是本次遷移的核心參照這里完整保留并逐條解釋// BEFOREnaga_oil 方言 #import bevy_pbr::forward_io::VertexOutput #import shaders/util.wgsl::hsv_to_rgb #ifdef VERTEX_COLORS varprivate tint: vec4f32; #endif group(2) binding(#{MATERIAL_BINDING}) varuniform color: vec4f32; // AFTERWESL import bevy_pbr::render::forward_io::VertexOutput; import super::util::hsv_to_rgb; if(VERTEX_COLORS) varprivate tint: vec4f32; group(2) binding(constants::MATERIAL_BINDING) varuniform color: vec4f32;映射關系可歸納為四類naga_oil 寫法WESL 寫法說明#import a::b::Cimport a::b::C;import 以分號結尾且必須置于文件最前#ifdef X…#endifif(X)無結束標記條件編譯直接附著在聲明上#{NAME}constants::NAME數值定義變成可讀常量#define_import_path移除導入路徑由文件位置自動推導1. import 語句位置與分號規(guī)則WESL 的import必須以分號結尾并且必須位于文件開頭出現(xiàn)在任何聲明或enable指令之前。這與 Rust 的use風格一致也和倉庫中引擎自帶著色器的實際寫法吻合例如 bevy_pbr 的 pbr.wesl 開篇就是一組importimport package::{ render::{ pbr_types, pbr_functions::alpha_discard, pbr_fragment::pbr_input_from_standard_material, }, decal::clustered::apply_decals, };此外 WESL 支持跨 crate 的具名導入如import bevy_core_pipeline::oit::draw::oit_draw;見 pbr.wesl。2. 模塊名與著色器在 crate 中的路徑一致指南指出模塊名現(xiàn)在必須與著色器文件在其 crate 中的路徑匹配。由于 Bevy 引擎的著色器被重組進了子目錄一批舊路徑發(fā)生了平移例如bevy_pbr::mesh_view_bindings→bevy_pbr::render::mesh_view_bindings對應 crates/bevy_pbr/src/render/mesh_view_bindings.weslbevy_pbr::prepass_utils→bevy_pbr::prepass::utils。這條規(guī)則的底層邏輯在 Shader::from_wesl 中非常清晰對于embedded://前綴的路徑Bevy 去掉協(xié)議前綴與文件擴展名后把路徑按/拆分成::分隔的模塊名——embedded://bevy_foo/bar.wesl因此成為可導入的bevy_foo::bar非內嵌著色器則生成以/開頭的資產路徑ShaderImport::AssetPath即指南所說的 “anything else at its asset path”其余著色器按資產路徑導入。對于項目內自定義著色器指南示例中的import super::util::hsv_to_rgb;展示了相對引用寫法shaders/util.wesl這樣的本地文件可以用super::util相對模塊名導入替代過去#import shaders/util.wgsl::hsv_to_rgb的字符串路徑。3. 條件編譯if 附著在語言元素上if/elif/else直接附著在完整的聲明、結構體成員、函數參數、import 乃至單條語句上不再需要#ifdef/#endif包裹塊。引擎著色器中的真實用例覆蓋了指南提到的所有附著位置附著結構體成員forward_io.wesl 中UncompressedVertex的每個頂點屬性都按能力開關裁掉struct UncompressedVertex { builtin(instance_index) instance_index: u32, if(VERTEX_POSITIONS) location(0) position: vec3f32, if(VERTEX_NORMALS) location(1) normal: vec3f32, ... if(VERTEX_COLORS) location(5) color: vec4f32, };附著函數參數pbr.wesl的 fragment 入口按管線階段裁剪入參if(MESHLET_MESH_MATERIAL_PASS)控制frag_coord是否存在附著 importpbr.wesl中 prepass 與 forward 兩條管線引用不同的輸入輸出類型if(PREPASS_PIPELINE) import package::{ prepass::io::{VertexOutput, FragmentOutput}, deferred::functions::deferred_output, }; else import package::render::{ forward_io::{VertexOutput, FragmentOutput}, ... };附著語句pbr.wesl的 fragment 體內用if(...)包裹逐語句邏輯。4. shader defs布爾變開關、數值變常量指南的關鍵一條布爾型著色器定義Bool變成條件編譯開關Int/UInt定義則同時可讀作constants::NAME常量并啟用一個同名開關。例如binding(#{MATERIAL_BINDING})改為binding(constants::MATERIAL_BINDING)值在編譯期由 Bevy 注入。這一機制在 ShaderCache::get 中有完整實現(xiàn)。編譯一個 WESL 著色器時收集定義閉包L229-L247從當前著色器出發(fā)沿imports圖做 BFS把依賴鏈上每個庫著色器自帶的shader_defs一并納入closure_defs——這意味著庫著色器里寫死的constants::取值會隨依賴自動傳播分流處理L248-L280Bool(key, v)寫入compiler_options.features.flags作為if開關Int/UInt除了啟用同名開關外還會把keyvalue追加進一張常量表生成虛擬constants模塊常量表被拼成const NAME value;形式的源碼L277-L280由 ShaderResolver::resolve_source 在解析到模塊名constants時注入因此constants::MATERIAL_BINDING在文本上就是普通 WGSL 的常量引用編譯輸出 WGSLwesl::compile_sourcemap以imports: true, condcomp: true的 CompileOptions 把模塊及其依賴拼成最終 WGSL 源再交給渲染器編譯。Int/UInt定義的常量用法在單元測試 constants_module 中得到驗證——group(constants::MATERIAL_BIND_GROUP)與arrayvec4f32, constants::BATCH_SIZE在給定ShaderDefVal::UInt后編譯產物中確實出現(xiàn)了對應的 2;與 4;。5.#define_import_path移除路徑即身份過去 naga_oil 需要#define_import_path手動聲明著色器的導入名現(xiàn)在該指令不復存在導入路徑完全由文件來源決定從embedded://加載的著色器按其crate 名 文件路徑可導入embedded://bevy_foo/bar.wesl即bevy_foo::bar其他著色器按其資產路徑可導入。對應的代碼證據是 scan_wesl_imports它解析 WESL 源碼中的每條import把Package來源的模塊路徑拼回crate::module::item形式的ShaderImport::Custom把Absolute來源拼回/a/b/c形式的ShaderImport::AssetPath從而讓資產系統(tǒng)能自動跟蹤導入依賴加載器中的依賴收集邏輯 會為每個AssetPath導入load_context.load一份強引用防止被引用文件提前釋放。特性開關與兼容邊界指南末尾給出了三條框架級變化逐條對應源碼事實shader_format_weslcargo feature 已移除WESL 支持始終啟用。WESL 是 bevy_shader 的無條件依賴wesl { version 0.4.2, features [naga-ext] }不再有任何開關GLSL 支持一并移除著色器源只保留Source::{Wgsl, Wesl, SpirV}三種形態(tài)SPIR-V 直通passthrough保持不變.spv文件依舊按字節(jié)直傳ShaderLoader 分派但如前所述SPIR-V 著色器不支持 shader defs且 ValidateShader 文檔中說明對不受信任的 SPIR-V 啟用運行期校驗會 panic。從源碼結構看緩存、重試與失效理解 WESL 管線的一個隱藏重點是導入解析的時序。著色器資產按加載先后入緩存若某個import的目標尚未加載完成get() 會返回ShaderImportNotYetAvailable下一幀重試import_retry 測試 驗證了這一“先失敗、后成功”的流程。其他幾個單測也很有參考價值library_def_scoping兩個庫著色器各自定義不同BATCH_SIZE3 與 7根著色器分別引用后各自的編譯產物只含自己的常量——說明常量閉包是按依賴圖精確收集的不會串值cyclic_import_invalidation循環(huán)導入的模塊被替換后依賴它的管線會全部被標記重編譯緩存失效傳播是閉環(huán)的import_resolution庫著色器熱替換后引用它的根著色器自動進入重編譯隊列。遷移操作清單結合指南與源碼一個自定義著色器例如倉庫 assets/shaders/custom_material.wesl 這類項目內文件的遷移步驟可以歸納為判斷是否需要遷移文件中不含#import/#ifdef/#{...}等預處理指令時保留.wgsl原樣即可否則執(zhí)行后續(xù)步驟重命名.wgsl→.wesl同步更新 Rust 側加載路徑ShaderRef/AssetPath中的擴展名翻譯指令#import X→import X;移到文件頂部、加分號#ifdef X ... #endif→ 在聲明前加if(X)無結束標記#{NAME}→constants::NAME修正模塊名引擎內置著色器按“crate 內文件路徑”重命名導入如bevy_pbr::render::forward_io本地文件用相對模塊名super::util或資產路徑引用刪除所有#define_import_path核對 shader defs確認布爾定義用于if開關數值定義ShaderDefVal::Int/UInt通過constants::NAME讀取驗證著色器源在 ShaderCache::get 中經wesl::compile_sourcemap產出 WGSL若導入缺失會輸出 “Shader...has an unresolved import” 警告每個著色器只告警一次見 L297-L305語法問題則以ProcessShaderError報錯并附帶可讀的診斷位置信息。小結這次遷移的本質是Bevy 把著色器的模塊系統(tǒng)、條件編譯和常量注入從外部預處理器naga_oil內化到了 WESL 語言本身import走資產系統(tǒng)、if走 WESL 條件編譯、constants::走虛擬常量模塊。純 WGSL 與 SPIR-V 兩條通路保持不變但只有 WESL 能享受 defs 與導入追蹤能力。對引擎作者而言bevy_pbr等模塊的.wesl文件是現(xiàn)成的、帶注釋的遷移范本對使用者而言照上文對照表逐條替換并核對模塊路徑即可完成遷移?!久赓M下載鏈接】bevyA refreshingly simple>項目地址: https://gitcode.com/GitHub_Trending/be/bevy創(chuàng)作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考