From 307e8dbd0e647ce742b702601b375efc08e7ebb4 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 2 Apr 2026 23:04:59 +0800 Subject: [PATCH] refactor: externalize builtin forward-lit shader asset --- .../shaders/forward-lit/forward-lit.frag.glsl | 36 ++++++++ .../forward-lit/forward-lit.frag.vk.glsl | 37 ++++++++ .../shaders/forward-lit/forward-lit.ps.hlsl | 36 ++++++++ .../shaders/forward-lit/forward-lit.shader | 53 +++++++++++ .../shaders/forward-lit/forward-lit.vert.glsl | 25 +++++ .../forward-lit/forward-lit.vert.vk.glsl | 25 +++++ .../shaders/forward-lit/forward-lit.vs.hlsl | 38 ++++++++ engine/src/Resources/BuiltinResources.cpp | 91 +++++++++++++++++++ tests/Resources/Shader/test_shader_loader.cpp | 21 +++++ 9 files changed, 362 insertions(+) create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.frag.glsl create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.frag.vk.glsl create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.ps.hlsl create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.shader create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.vert.glsl create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.vert.vk.glsl create mode 100644 engine/assets/builtin/shaders/forward-lit/forward-lit.vs.hlsl diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.glsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.glsl new file mode 100644 index 00000000..f31a2210 --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.glsl @@ -0,0 +1,36 @@ +// XC_BUILTIN_FORWARD_LIT_OPENGL_PS +#version 430 +layout(binding = 1) uniform sampler2D uBaseColorTexture; + +layout(std140, binding = 1) uniform PerObjectConstants { + mat4 gProjectionMatrix; + mat4 gViewMatrix; + mat4 gModelMatrix; + mat4 gNormalMatrix; + vec4 gMainLightDirectionAndIntensity; + vec4 gMainLightColorAndFlags; +}; + +layout(std140, binding = 2) uniform MaterialConstants { + vec4 gBaseColorFactor; +}; + +in vec3 vNormalWS; +in vec2 vTexCoord; + +layout(location = 0) out vec4 fragColor; + +void main() { + vec4 baseColor = texture(uBaseColorTexture, vTexCoord) * gBaseColorFactor; + if (gMainLightColorAndFlags.w < 0.5) { + fragColor = baseColor; + return; + } + + vec3 normalWS = normalize(vNormalWS); + vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz); + float diffuse = max(dot(normalWS, directionToLightWS), 0.0); + vec3 lighting = vec3(0.28) + + gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w); + fragColor = vec4(baseColor.rgb * lighting, baseColor.a); +} diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.vk.glsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.vk.glsl new file mode 100644 index 00000000..88d41435 --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.frag.vk.glsl @@ -0,0 +1,37 @@ +// XC_BUILTIN_FORWARD_LIT_VULKAN_PS +#version 450 +layout(set = 3, binding = 0) uniform texture2D uBaseColorTexture; +layout(set = 4, binding = 0) uniform sampler uLinearSampler; + +layout(set = 1, binding = 0, std140) uniform PerObjectConstants { + mat4 gProjectionMatrix; + mat4 gViewMatrix; + mat4 gModelMatrix; + mat4 gNormalMatrix; + vec4 gMainLightDirectionAndIntensity; + vec4 gMainLightColorAndFlags; +}; + +layout(set = 2, binding = 0, std140) uniform MaterialConstants { + vec4 gBaseColorFactor; +}; + +layout(location = 0) in vec3 vNormalWS; +layout(location = 1) in vec2 vTexCoord; + +layout(location = 0) out vec4 fragColor; + +void main() { + vec4 baseColor = texture(sampler2D(uBaseColorTexture, uLinearSampler), vTexCoord) * gBaseColorFactor; + if (gMainLightColorAndFlags.w < 0.5) { + fragColor = baseColor; + return; + } + + vec3 normalWS = normalize(vNormalWS); + vec3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz); + float diffuse = max(dot(normalWS, directionToLightWS), 0.0); + vec3 lighting = vec3(0.28) + + gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w); + fragColor = vec4(baseColor.rgb * lighting, baseColor.a); +} diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.ps.hlsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.ps.hlsl new file mode 100644 index 00000000..aa16ea10 --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.ps.hlsl @@ -0,0 +1,36 @@ +// XC_BUILTIN_FORWARD_LIT_D3D12_PS +Texture2D gBaseColorTexture : register(t1); +SamplerState gLinearSampler : register(s1); + +cbuffer PerObjectConstants : register(b1) { + float4x4 gProjectionMatrix; + float4x4 gViewMatrix; + float4x4 gModelMatrix; + float4x4 gNormalMatrix; + float4 gMainLightDirectionAndIntensity; + float4 gMainLightColorAndFlags; +}; + +cbuffer MaterialConstants : register(b2) { + float4 gBaseColorFactor; +}; + +struct PSInput { + float4 position : SV_POSITION; + float3 normalWS : TEXCOORD0; + float2 texcoord : TEXCOORD1; +}; + +float4 MainPS(PSInput input) : SV_TARGET { + float4 baseColor = gBaseColorTexture.Sample(gLinearSampler, input.texcoord) * gBaseColorFactor; + if (gMainLightColorAndFlags.a < 0.5f) { + return baseColor; + } + + float3 normalWS = normalize(input.normalWS); + float3 directionToLightWS = normalize(gMainLightDirectionAndIntensity.xyz); + float diffuse = saturate(dot(normalWS, directionToLightWS)); + float3 lighting = float3(0.28f, 0.28f, 0.28f) + + gMainLightColorAndFlags.rgb * (diffuse * gMainLightDirectionAndIntensity.w); + return float4(baseColor.rgb * lighting, baseColor.a); +} diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.shader b/engine/assets/builtin/shaders/forward-lit/forward-lit.shader new file mode 100644 index 00000000..ab956556 --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.shader @@ -0,0 +1,53 @@ +{ + "name": "Builtin Forward Lit", + "passes": [ + { + "name": "ForwardLit", + "tags": { + "LightMode": "ForwardBase" + }, + "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/forward-lit/forward-lit.vert.glsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.vert.glsl new file mode 100644 index 00000000..e24c6e6c --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.vert.glsl @@ -0,0 +1,25 @@ +// XC_BUILTIN_FORWARD_LIT_OPENGL_VS +#version 430 +layout(location = 0) in vec3 aPosition; +layout(location = 1) in vec3 aNormal; +layout(location = 2) in vec2 aTexCoord; + +layout(std140, binding = 1) uniform PerObjectConstants { + mat4 gProjectionMatrix; + mat4 gViewMatrix; + mat4 gModelMatrix; + mat4 gNormalMatrix; + vec4 gMainLightDirectionAndIntensity; + vec4 gMainLightColorAndFlags; +}; + +out vec3 vNormalWS; +out vec2 vTexCoord; + +void main() { + vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0); + vec4 positionVS = gViewMatrix * positionWS; + gl_Position = gProjectionMatrix * positionVS; + vNormalWS = mat3(gNormalMatrix) * aNormal; + vTexCoord = aTexCoord; +} diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.vert.vk.glsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.vert.vk.glsl new file mode 100644 index 00000000..0a2dab29 --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.vert.vk.glsl @@ -0,0 +1,25 @@ +// XC_BUILTIN_FORWARD_LIT_VULKAN_VS +#version 450 +layout(location = 0) in vec3 aPosition; +layout(location = 1) in vec3 aNormal; +layout(location = 2) in vec2 aTexCoord; + +layout(set = 1, binding = 0, std140) uniform PerObjectConstants { + mat4 gProjectionMatrix; + mat4 gViewMatrix; + mat4 gModelMatrix; + mat4 gNormalMatrix; + vec4 gMainLightDirectionAndIntensity; + vec4 gMainLightColorAndFlags; +}; + +layout(location = 0) out vec3 vNormalWS; +layout(location = 1) out vec2 vTexCoord; + +void main() { + vec4 positionWS = gModelMatrix * vec4(aPosition, 1.0); + vec4 positionVS = gViewMatrix * positionWS; + gl_Position = gProjectionMatrix * positionVS; + vNormalWS = mat3(gNormalMatrix) * aNormal; + vTexCoord = aTexCoord; +} diff --git a/engine/assets/builtin/shaders/forward-lit/forward-lit.vs.hlsl b/engine/assets/builtin/shaders/forward-lit/forward-lit.vs.hlsl new file mode 100644 index 00000000..310eebcc --- /dev/null +++ b/engine/assets/builtin/shaders/forward-lit/forward-lit.vs.hlsl @@ -0,0 +1,38 @@ +// XC_BUILTIN_FORWARD_LIT_D3D12_VS +Texture2D gBaseColorTexture : register(t1); +SamplerState gLinearSampler : register(s1); + +cbuffer PerObjectConstants : register(b1) { + float4x4 gProjectionMatrix; + float4x4 gViewMatrix; + float4x4 gModelMatrix; + float4x4 gNormalMatrix; + float4 gMainLightDirectionAndIntensity; + float4 gMainLightColorAndFlags; +}; + +cbuffer MaterialConstants : register(b2) { + float4 gBaseColorFactor; +}; + +struct VSInput { + float3 position : POSITION; + float3 normal : NORMAL; + float2 texcoord : TEXCOORD0; +}; + +struct PSInput { + float4 position : SV_POSITION; + float3 normalWS : TEXCOORD0; + float2 texcoord : TEXCOORD1; +}; + +PSInput MainVS(VSInput input) { + PSInput output; + float4 positionWS = mul(gModelMatrix, float4(input.position, 1.0f)); + float4 positionVS = mul(gViewMatrix, positionWS); + output.position = mul(gProjectionMatrix, positionVS); + output.normalWS = mul((float3x3)gNormalMatrix, input.normal); + output.texcoord = input.texcoord; + return output; +} diff --git a/engine/src/Resources/BuiltinResources.cpp b/engine/src/Resources/BuiltinResources.cpp index dd826aed..9ad2c6b6 100644 --- a/engine/src/Resources/BuiltinResources.cpp +++ b/engine/src/Resources/BuiltinResources.cpp @@ -7,10 +7,13 @@ #include #include #include +#include #include #include #include +#include +#include #include namespace XCEngine { @@ -36,6 +39,87 @@ struct MeshBuffers { std::vector indices; }; +size_t CalculateBuiltinShaderMemorySize(const Shader& shader); + +constexpr const char* kBuiltinForwardLitShaderManifestRelativePath = + "engine/assets/builtin/shaders/forward-lit/forward-lit.shader"; + +Containers::String NormalizeBuiltinAssetPath(const std::filesystem::path& path) { + return Containers::String(path.lexically_normal().generic_string().c_str()); +} + +bool TryResolveBuiltinAssetPathFromAnchor( + const std::filesystem::path& anchor, + const std::filesystem::path& relativePath, + std::filesystem::path& outPath) { + if (anchor.empty()) { + return false; + } + + std::error_code ec; + std::filesystem::path current = anchor.lexically_normal(); + if (std::filesystem::is_regular_file(current, ec)) { + current = current.parent_path(); + } + + while (!current.empty()) { + const std::filesystem::path candidate = (current / relativePath).lexically_normal(); + if (std::filesystem::exists(candidate, ec)) { + outPath = candidate; + return true; + } + + const std::filesystem::path parent = current.parent_path(); + if (parent == current) { + break; + } + current = parent; + } + + return false; +} + +bool TryResolveBuiltinForwardLitShaderManifestPath(Containers::String& outPath) { + const std::filesystem::path relativePath(kBuiltinForwardLitShaderManifestRelativePath); + std::filesystem::path resolvedPath; + std::error_code ec; + + if (TryResolveBuiltinAssetPathFromAnchor(std::filesystem::current_path(ec), relativePath, resolvedPath)) { + outPath = NormalizeBuiltinAssetPath(resolvedPath); + return true; + } + + const Containers::String& resourceRoot = ResourceManager::Get().GetResourceRoot(); + if (!resourceRoot.Empty() && + TryResolveBuiltinAssetPathFromAnchor(std::filesystem::path(resourceRoot.CStr()), relativePath, resolvedPath)) { + outPath = NormalizeBuiltinAssetPath(resolvedPath); + return true; + } + + if (TryResolveBuiltinAssetPathFromAnchor(std::filesystem::path(__FILE__), relativePath, resolvedPath)) { + outPath = NormalizeBuiltinAssetPath(resolvedPath); + return true; + } + + return false; +} + +Shader* LoadBuiltinShaderFromManifest( + const Containers::String& builtinPath, + const Containers::String& manifestPath) { + ShaderLoader shaderLoader; + LoadResult result = shaderLoader.Load(manifestPath); + if (!result || result.resource == nullptr) { + return nullptr; + } + + auto* shader = static_cast(result.resource); + shader->m_path = builtinPath; + shader->m_guid = ResourceGUID::Generate(builtinPath); + shader->m_memorySize = CalculateBuiltinShaderMemorySize(*shader); + return shader; +} + const char kBuiltinForwardHlsl[] = R"( Texture2D gBaseColorTexture : register(t1); SamplerState gLinearSampler : register(s1); @@ -1049,6 +1133,13 @@ size_t CalculateBuiltinShaderMemorySize(const Shader& shader) { } Shader* BuildBuiltinForwardLitShader(const Containers::String& path) { + Containers::String manifestPath; + if (TryResolveBuiltinForwardLitShaderManifestPath(manifestPath)) { + if (Shader* shader = LoadBuiltinShaderFromManifest(path, manifestPath)) { + return shader; + } + } + auto* shader = new Shader(); IResource::ConstructParams params; params.name = Containers::String("Builtin Forward Lit"); diff --git a/tests/Resources/Shader/test_shader_loader.cpp b/tests/Resources/Shader/test_shader_loader.cpp index 31d7e049..4650f79f 100644 --- a/tests/Resources/Shader/test_shader_loader.cpp +++ b/tests/Resources/Shader/test_shader_loader.cpp @@ -264,6 +264,27 @@ TEST(ShaderLoader, LoadBuiltinForwardLitShaderBuildsBackendVariants) { EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Vertex, ShaderBackend::Vulkan), nullptr); EXPECT_NE(shader->FindVariant("ForwardLit", ShaderType::Fragment, ShaderBackend::Vulkan), nullptr); + const ShaderStageVariant* d3d12Vertex = shader->FindVariant( + "ForwardLit", + ShaderType::Vertex, + ShaderBackend::D3D12); + ASSERT_NE(d3d12Vertex, nullptr); + EXPECT_NE(std::string(d3d12Vertex->sourceCode.CStr()).find("XC_BUILTIN_FORWARD_LIT_D3D12_VS"), std::string::npos); + + const ShaderStageVariant* openglFragment = shader->FindVariant( + "ForwardLit", + ShaderType::Fragment, + ShaderBackend::OpenGL); + ASSERT_NE(openglFragment, nullptr); + EXPECT_NE(std::string(openglFragment->sourceCode.CStr()).find("XC_BUILTIN_FORWARD_LIT_OPENGL_PS"), std::string::npos); + + const ShaderStageVariant* vulkanFragment = shader->FindVariant( + "ForwardLit", + ShaderType::Fragment, + ShaderBackend::Vulkan); + ASSERT_NE(vulkanFragment, nullptr); + EXPECT_NE(std::string(vulkanFragment->sourceCode.CStr()).find("XC_BUILTIN_FORWARD_LIT_VULKAN_PS"), std::string::npos); + delete shader; }