diff --git a/docs/plan/Shader与Material系统下一阶段计划.md b/docs/plan/Shader与Material系统下一阶段计划.md index 5cb098d2..9cb232b7 100644 --- a/docs/plan/Shader与Material系统下一阶段计划.md +++ b/docs/plan/Shader与Material系统下一阶段计划.md @@ -475,8 +475,13 @@ Unity-like Shader Authoring (.shader) - `ShaderLoader` 新增 Unity-like `.shader` authoring 识别与解析入口,但保留现有 JSON manifest `.shader` 兼容路径不动 - importer 继续落到现有 runtime shader contract:`properties / passes / resources / backend variants` - `CollectSourceDependencies` 已覆盖新 authoring 路径,`AssetDatabase` 会继续追踪各 backend stage 文件依赖并参与重导入 +- 已完成:Step 2 `builtin shader 迁到新 authoring 入口` + - `forward-lit / unlit / object-id / depth-only / shadow-caster` 五个 builtin `.shader` 入口已全部切到 Unity-like authoring + - stage 源文件、builtin shader 路径与 renderer 消费 contract 保持不变,迁移只发生在 authoring 入口层 + - 补充 `DepthOnly / ShadowCaster` builtin shader loader 覆盖,确保五类 builtin pass 都经过新 authoring 路径验证 - 已验证:`shader_tests` 中新增 authoring 直载与 artifact/reimport 覆盖 -- 下一步:进入 Step 2,把 builtin shader 逐步迁到新 authoring 入口,并确保 renderer 消费路径与当前 contract 保持一致 +- 已验证:`shader_tests` 31/31 通过,builtin `ForwardLit / Unlit / ObjectId / DepthOnly / ShadowCaster` 全部通过加载与 backend variant 覆盖 +- 下一步:进入 Step 3,继续收紧 material 主路径,把 imported shader schema 变成 material 的正式主执行路径 当前阶段明确不做: diff --git a/engine/assets/builtin/shaders/depth-only/depth-only.shader b/engine/assets/builtin/shaders/depth-only/depth-only.shader index a94f1584..a098fdff 100644 --- a/engine/assets/builtin/shaders/depth-only/depth-only.shader +++ b/engine/assets/builtin/shaders/depth-only/depth-only.shader @@ -1,62 +1,22 @@ +Shader "Builtin Depth Only" { - "name": "Builtin Depth Only", - "passes": [ + SubShader { - "name": "DepthOnly", - "tags": { - "LightMode": "DepthOnly" - }, - "resources": [ + Pass { - "name": "PerObjectConstants", - "type": "ConstantBuffer", - "set": 0, - "binding": 0, - "semantic": "PerObject" + Name "DepthOnly" + Tags { "LightMode" = "DepthOnly" } + Resources + { + PerObjectConstants (ConstantBuffer, 0, 0) [Semantic(PerObject)] + } + HLSLPROGRAM + #pragma vertex MainVS + #pragma fragment MainPS + #pragma backend D3D12 HLSL "depth-only.vs.hlsl" "depth-only.ps.hlsl" vs_5_0 ps_5_0 + #pragma backend OpenGL GLSL "depth-only.vert.glsl" "depth-only.frag.glsl" + #pragma backend Vulkan GLSL "depth-only.vert.vk.glsl" "depth-only.frag.vk.glsl" + ENDHLSL } - ], - "variants": [ - { - "stage": "Vertex", - "backend": "D3D12", - "language": "HLSL", - "source": "depth-only.vs.hlsl", - "entryPoint": "MainVS", - "profile": "vs_5_0" - }, - { - "stage": "Fragment", - "backend": "D3D12", - "language": "HLSL", - "source": "depth-only.ps.hlsl", - "entryPoint": "MainPS", - "profile": "ps_5_0" - }, - { - "stage": "Vertex", - "backend": "OpenGL", - "language": "GLSL", - "source": "depth-only.vert.glsl" - }, - { - "stage": "Fragment", - "backend": "OpenGL", - "language": "GLSL", - "source": "depth-only.frag.glsl" - }, - { - "stage": "Vertex", - "backend": "Vulkan", - "language": "GLSL", - "source": "depth-only.vert.vk.glsl" - }, - { - "stage": "Fragment", - "backend": "Vulkan", - "language": "GLSL", - "source": "depth-only.frag.vk.glsl" - } - ] } - ] } diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.shader b/engine/assets/builtin/shaders/forward-lit/forward-lit.shader index e2460703..bfae040e 100644 --- a/engine/assets/builtin/shaders/forward-lit/forward-lit.shader +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.shader @@ -1,99 +1,30 @@ +Shader "Builtin Forward Lit" { - "name": "Builtin Forward Lit", - "properties": [ + Properties { - "name": "_BaseColor", - "displayName": "Base Color", - "type": "Color", - "defaultValue": "(1,1,1,1)", - "semantic": "BaseColor" - }, - { - "name": "_MainTex", - "displayName": "Base Map", - "type": "2D", - "defaultValue": "white", - "semantic": "BaseColorTexture" + _BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)] + _MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)] } - ], - "passes": [ + SubShader { - "name": "ForwardLit", - "tags": { - "LightMode": "ForwardBase" - }, - "resources": [ + Pass { - "name": "PerObjectConstants", - "type": "ConstantBuffer", - "set": 1, - "binding": 0, - "semantic": "PerObject" - }, - { - "name": "MaterialConstants", - "type": "ConstantBuffer", - "set": 2, - "binding": 0, - "semantic": "Material" - }, - { - "name": "BaseColorTexture", - "type": "Texture2D", - "set": 3, - "binding": 0, - "semantic": "BaseColorTexture" - }, - { - "name": "LinearClampSampler", - "type": "Sampler", - "set": 4, - "binding": 0, - "semantic": "LinearClampSampler" + Name "ForwardLit" + Tags { "LightMode" = "ForwardBase" } + Resources + { + PerObjectConstants (ConstantBuffer, 1, 0) [Semantic(PerObject)] + MaterialConstants (ConstantBuffer, 2, 0) [Semantic(Material)] + BaseColorTexture (Texture2D, 3, 0) [Semantic(BaseColorTexture)] + LinearClampSampler (Sampler, 4, 0) [Semantic(LinearClampSampler)] + } + HLSLPROGRAM + #pragma vertex MainVS + #pragma fragment MainPS + #pragma backend D3D12 HLSL "forward-lit.vs.hlsl" "forward-lit.ps.hlsl" vs_5_0 ps_5_0 + #pragma backend OpenGL GLSL "forward-lit.vert.glsl" "forward-lit.frag.glsl" + #pragma backend Vulkan GLSL "forward-lit.vert.vk.glsl" "forward-lit.frag.vk.glsl" + ENDHLSL } - ], - "variants": [ - { - "stage": "Vertex", - "backend": "D3D12", - "language": "HLSL", - "source": "forward-lit.vs.hlsl", - "entryPoint": "MainVS", - "profile": "vs_5_0" - }, - { - "stage": "Fragment", - "backend": "D3D12", - "language": "HLSL", - "source": "forward-lit.ps.hlsl", - "entryPoint": "MainPS", - "profile": "ps_5_0" - }, - { - "stage": "Vertex", - "backend": "OpenGL", - "language": "GLSL", - "source": "forward-lit.vert.glsl" - }, - { - "stage": "Fragment", - "backend": "OpenGL", - "language": "GLSL", - "source": "forward-lit.frag.glsl" - }, - { - "stage": "Vertex", - "backend": "Vulkan", - "language": "GLSL", - "source": "forward-lit.vert.vk.glsl" - }, - { - "stage": "Fragment", - "backend": "Vulkan", - "language": "GLSL", - "source": "forward-lit.frag.vk.glsl" - } - ] } - ] } diff --git a/engine/assets/builtin/shaders/object-id/object-id.shader b/engine/assets/builtin/shaders/object-id/object-id.shader index 2f272a7c..d84c5752 100644 --- a/engine/assets/builtin/shaders/object-id/object-id.shader +++ b/engine/assets/builtin/shaders/object-id/object-id.shader @@ -1,62 +1,22 @@ +Shader "Builtin Object Id" { - "name": "Builtin Object Id", - "passes": [ + SubShader { - "name": "ObjectId", - "tags": { - "LightMode": "ObjectId" - }, - "resources": [ + Pass { - "name": "PerObjectConstants", - "type": "ConstantBuffer", - "set": 0, - "binding": 0, - "semantic": "PerObject" + Name "ObjectId" + Tags { "LightMode" = "ObjectId" } + Resources + { + PerObjectConstants (ConstantBuffer, 0, 0) [Semantic(PerObject)] + } + HLSLPROGRAM + #pragma vertex MainVS + #pragma fragment MainPS + #pragma backend D3D12 HLSL "object-id.vs.hlsl" "object-id.ps.hlsl" vs_5_0 ps_5_0 + #pragma backend OpenGL GLSL "object-id.vert.glsl" "object-id.frag.glsl" + #pragma backend Vulkan GLSL "object-id.vert.vk.glsl" "object-id.frag.vk.glsl" + ENDHLSL } - ], - "variants": [ - { - "stage": "Vertex", - "backend": "D3D12", - "language": "HLSL", - "source": "object-id.vs.hlsl", - "entryPoint": "MainVS", - "profile": "vs_5_0" - }, - { - "stage": "Fragment", - "backend": "D3D12", - "language": "HLSL", - "source": "object-id.ps.hlsl", - "entryPoint": "MainPS", - "profile": "ps_5_0" - }, - { - "stage": "Vertex", - "backend": "OpenGL", - "language": "GLSL", - "source": "object-id.vert.glsl" - }, - { - "stage": "Fragment", - "backend": "OpenGL", - "language": "GLSL", - "source": "object-id.frag.glsl" - }, - { - "stage": "Vertex", - "backend": "Vulkan", - "language": "GLSL", - "source": "object-id.vert.vk.glsl" - }, - { - "stage": "Fragment", - "backend": "Vulkan", - "language": "GLSL", - "source": "object-id.frag.vk.glsl" - } - ] } - ] } diff --git a/engine/assets/builtin/shaders/shadow-caster/shadow-caster.shader b/engine/assets/builtin/shaders/shadow-caster/shadow-caster.shader index 34f514d4..d5a0244a 100644 --- a/engine/assets/builtin/shaders/shadow-caster/shadow-caster.shader +++ b/engine/assets/builtin/shaders/shadow-caster/shadow-caster.shader @@ -1,62 +1,22 @@ +Shader "Builtin Shadow Caster" { - "name": "Builtin Shadow Caster", - "passes": [ + SubShader { - "name": "ShadowCaster", - "tags": { - "LightMode": "ShadowCaster" - }, - "resources": [ + Pass { - "name": "PerObjectConstants", - "type": "ConstantBuffer", - "set": 0, - "binding": 0, - "semantic": "PerObject" + Name "ShadowCaster" + Tags { "LightMode" = "ShadowCaster" } + Resources + { + PerObjectConstants (ConstantBuffer, 0, 0) [Semantic(PerObject)] + } + HLSLPROGRAM + #pragma vertex MainVS + #pragma fragment MainPS + #pragma backend D3D12 HLSL "shadow-caster.vs.hlsl" "shadow-caster.ps.hlsl" vs_5_0 ps_5_0 + #pragma backend OpenGL GLSL "shadow-caster.vert.glsl" "shadow-caster.frag.glsl" + #pragma backend Vulkan GLSL "shadow-caster.vert.vk.glsl" "shadow-caster.frag.vk.glsl" + ENDHLSL } - ], - "variants": [ - { - "stage": "Vertex", - "backend": "D3D12", - "language": "HLSL", - "source": "shadow-caster.vs.hlsl", - "entryPoint": "MainVS", - "profile": "vs_5_0" - }, - { - "stage": "Fragment", - "backend": "D3D12", - "language": "HLSL", - "source": "shadow-caster.ps.hlsl", - "entryPoint": "MainPS", - "profile": "ps_5_0" - }, - { - "stage": "Vertex", - "backend": "OpenGL", - "language": "GLSL", - "source": "shadow-caster.vert.glsl" - }, - { - "stage": "Fragment", - "backend": "OpenGL", - "language": "GLSL", - "source": "shadow-caster.frag.glsl" - }, - { - "stage": "Vertex", - "backend": "Vulkan", - "language": "GLSL", - "source": "shadow-caster.vert.vk.glsl" - }, - { - "stage": "Fragment", - "backend": "Vulkan", - "language": "GLSL", - "source": "shadow-caster.frag.vk.glsl" - } - ] } - ] } diff --git a/engine/assets/builtin/shaders/unlit/unlit.shader b/engine/assets/builtin/shaders/unlit/unlit.shader index d54ea442..ce7aa251 100644 --- a/engine/assets/builtin/shaders/unlit/unlit.shader +++ b/engine/assets/builtin/shaders/unlit/unlit.shader @@ -1,99 +1,30 @@ +Shader "Builtin Unlit" { - "name": "Builtin Unlit", - "properties": [ + Properties { - "name": "_BaseColor", - "displayName": "Base Color", - "type": "Color", - "defaultValue": "(1,1,1,1)", - "semantic": "BaseColor" - }, - { - "name": "_MainTex", - "displayName": "Base Map", - "type": "2D", - "defaultValue": "white", - "semantic": "BaseColorTexture" + _BaseColor ("Base Color", Color) = (1,1,1,1) [Semantic(BaseColor)] + _MainTex ("Base Map", 2D) = "white" [Semantic(BaseColorTexture)] } - ], - "passes": [ + SubShader { - "name": "Unlit", - "tags": { - "LightMode": "Unlit" - }, - "resources": [ + Pass { - "name": "PerObjectConstants", - "type": "ConstantBuffer", - "set": 1, - "binding": 0, - "semantic": "PerObject" - }, - { - "name": "MaterialConstants", - "type": "ConstantBuffer", - "set": 2, - "binding": 0, - "semantic": "Material" - }, - { - "name": "BaseColorTexture", - "type": "Texture2D", - "set": 3, - "binding": 0, - "semantic": "BaseColorTexture" - }, - { - "name": "LinearClampSampler", - "type": "Sampler", - "set": 4, - "binding": 0, - "semantic": "LinearClampSampler" + Name "Unlit" + Tags { "LightMode" = "Unlit" } + Resources + { + PerObjectConstants (ConstantBuffer, 1, 0) [Semantic(PerObject)] + MaterialConstants (ConstantBuffer, 2, 0) [Semantic(Material)] + BaseColorTexture (Texture2D, 3, 0) [Semantic(BaseColorTexture)] + LinearClampSampler (Sampler, 4, 0) [Semantic(LinearClampSampler)] + } + HLSLPROGRAM + #pragma vertex MainVS + #pragma fragment MainPS + #pragma backend D3D12 HLSL "unlit.vs.hlsl" "unlit.ps.hlsl" vs_5_0 ps_5_0 + #pragma backend OpenGL GLSL "unlit.vert.glsl" "unlit.frag.glsl" + #pragma backend Vulkan GLSL "unlit.vert.vk.glsl" "unlit.frag.vk.glsl" + ENDHLSL } - ], - "variants": [ - { - "stage": "Vertex", - "backend": "D3D12", - "language": "HLSL", - "source": "unlit.vs.hlsl", - "entryPoint": "MainVS", - "profile": "vs_5_0" - }, - { - "stage": "Fragment", - "backend": "D3D12", - "language": "HLSL", - "source": "unlit.ps.hlsl", - "entryPoint": "MainPS", - "profile": "ps_5_0" - }, - { - "stage": "Vertex", - "backend": "OpenGL", - "language": "GLSL", - "source": "unlit.vert.glsl" - }, - { - "stage": "Fragment", - "backend": "OpenGL", - "language": "GLSL", - "source": "unlit.frag.glsl" - }, - { - "stage": "Vertex", - "backend": "Vulkan", - "language": "GLSL", - "source": "unlit.vert.vk.glsl" - }, - { - "stage": "Fragment", - "backend": "Vulkan", - "language": "GLSL", - "source": "unlit.frag.vk.glsl" - } - ] } - ] } diff --git a/tests/Resources/Shader/test_shader_loader.cpp b/tests/Resources/Shader/test_shader_loader.cpp index 0b8ab2de..de083f37 100644 --- a/tests/Resources/Shader/test_shader_loader.cpp +++ b/tests/Resources/Shader/test_shader_loader.cpp @@ -844,6 +844,118 @@ TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsBackendVariants) { delete shader; } +TEST(ShaderLoader, LoadBuiltinDepthOnlyShaderBuildsBackendVariants) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinDepthOnlyShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + ASSERT_TRUE(shader->IsValid()); + + const ShaderPass* pass = shader->FindPass("DepthOnly"); + ASSERT_NE(pass, nullptr); + ASSERT_EQ(pass->resources.Size(), 1u); + EXPECT_EQ(pass->resources[0].semantic, "PerObject"); + EXPECT_EQ(pass->resources[0].type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(pass->resources[0].set, 0u); + EXPECT_EQ(pass->resources[0].binding, 0u); + ASSERT_EQ(pass->variants.Size(), 6u); + ASSERT_EQ(pass->tags.Size(), 1u); + EXPECT_EQ(pass->tags[0].name, "LightMode"); + EXPECT_EQ(pass->tags[0].value, "DepthOnly"); + + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); + EXPECT_NE(shader->FindVariant("DepthOnly", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); + + const ShaderStageVariant* d3d12Vertex = shader->FindVariant( + "DepthOnly", + ShaderType::Vertex, + ShaderBackend::D3D12); + ASSERT_NE(d3d12Vertex, nullptr); + EXPECT_NE(std::string(d3d12Vertex->sourceCode.CStr()).find("XC_BUILTIN_DEPTH_ONLY_D3D12_VS"), std::string::npos); + + const ShaderStageVariant* openglFragment = shader->FindVariant( + "DepthOnly", + ShaderType::Fragment, + ShaderBackend::OpenGL); + ASSERT_NE(openglFragment, nullptr); + EXPECT_NE(std::string(openglFragment->sourceCode.CStr()).find("XC_BUILTIN_DEPTH_ONLY_OPENGL_PS"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "DepthOnly", + ShaderType::Fragment, + ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("XC_BUILTIN_DEPTH_ONLY_VULKAN_PS"), std::string::npos); + + delete shader; +} + +TEST(ShaderLoader, LoadBuiltinShadowCasterShaderBuildsBackendVariants) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinShadowCasterShaderPath()); + ASSERT_TRUE(result); + ASSERT_NE(result.resource, nullptr); + + Shader* shader = static_cast(result.resource); + ASSERT_NE(shader, nullptr); + ASSERT_TRUE(shader->IsValid()); + + const ShaderPass* pass = shader->FindPass("ShadowCaster"); + ASSERT_NE(pass, nullptr); + ASSERT_EQ(pass->resources.Size(), 1u); + EXPECT_EQ(pass->resources[0].semantic, "PerObject"); + EXPECT_EQ(pass->resources[0].type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(pass->resources[0].set, 0u); + EXPECT_EQ(pass->resources[0].binding, 0u); + ASSERT_EQ(pass->variants.Size(), 6u); + ASSERT_EQ(pass->tags.Size(), 1u); + EXPECT_EQ(pass->tags[0].name, "LightMode"); + EXPECT_EQ(pass->tags[0].value, "ShadowCaster"); + + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); + EXPECT_NE(shader->FindVariant("ShadowCaster", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); + + const ShaderStageVariant* d3d12Vertex = shader->FindVariant( + "ShadowCaster", + ShaderType::Vertex, + ShaderBackend::D3D12); + ASSERT_NE(d3d12Vertex, nullptr); + EXPECT_NE( + std::string(d3d12Vertex->sourceCode.CStr()).find("XC_BUILTIN_SHADOW_CASTER_D3D12_VS"), + std::string::npos); + + const ShaderStageVariant* openglFragment = shader->FindVariant( + "ShadowCaster", + ShaderType::Fragment, + ShaderBackend::OpenGL); + ASSERT_NE(openglFragment, nullptr); + EXPECT_NE( + std::string(openglFragment->sourceCode.CStr()).find("XC_BUILTIN_SHADOW_CASTER_OPENGL_PS"), + std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "ShadowCaster", + ShaderType::Fragment, + ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + EXPECT_NE( + std::string(vulkanFragment->sourceCode.CStr()).find("XC_BUILTIN_SHADOW_CASTER_VULKAN_PS"), + std::string::npos); + + delete shader; +} + TEST(ShaderLoader, ResourceManagerLazilyLoadsBuiltinForwardLitShader) { ResourceManager& manager = ResourceManager::Get(); manager.Shutdown();