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