From b2d0570b1b2b637c236ce515d0462027299d5dc1 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 2 Apr 2026 19:32:15 +0800 Subject: [PATCH] refactor: route builtin infinite grid through shader assets --- .../Passes/BuiltinInfiniteGridPass.h | 4 + .../XCEngine/Resources/BuiltinResources.h | 1 + .../Passes/BuiltinInfiniteGridPass.cpp | 215 +++++------------- engine/src/Resources/BuiltinResources.cpp | 188 +++++++++++++++ tests/Resources/Shader/test_shader_loader.cpp | 30 +++ 5 files changed, 278 insertions(+), 160 deletions(-) diff --git a/engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h b/engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h index eca7b57f..23e9664c 100644 --- a/engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h +++ b/engine/include/XCEngine/Rendering/Passes/BuiltinInfiniteGridPass.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include @@ -9,6 +11,7 @@ #include #include #include +#include namespace XCEngine { namespace Rendering { @@ -57,6 +60,7 @@ private: RHI::RHIPipelineState* m_pipelineState = nullptr; RHI::RHIDescriptorPool* m_constantPool = nullptr; RHI::RHIDescriptorSet* m_constantSet = nullptr; + Resources::ResourceHandle m_builtinInfiniteGridShader; }; } // namespace Passes diff --git a/engine/include/XCEngine/Resources/BuiltinResources.h b/engine/include/XCEngine/Resources/BuiltinResources.h index 59853b6b..650e9238 100644 --- a/engine/include/XCEngine/Resources/BuiltinResources.h +++ b/engine/include/XCEngine/Resources/BuiltinResources.h @@ -25,6 +25,7 @@ Containers::String GetBuiltinPrimitiveMeshPath(BuiltinPrimitiveType primitiveTyp Containers::String GetBuiltinDefaultPrimitiveMaterialPath(); Containers::String GetBuiltinForwardLitShaderPath(); Containers::String GetBuiltinObjectIdShaderPath(); +Containers::String GetBuiltinInfiniteGridShaderPath(); Containers::String GetBuiltinDefaultPrimitiveTexturePath(); bool TryParseBuiltinPrimitiveType(const Containers::String& path, BuiltinPrimitiveType& outPrimitiveType); diff --git a/engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp b/engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp index 7f5f3f46..e035abf1 100644 --- a/engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp +++ b/engine/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp @@ -2,12 +2,16 @@ #include #include +#include +#include #include #include +#include + +#include "Rendering/Detail/ShaderVariantUtils.h" #include #include -#include namespace XCEngine { namespace Rendering { @@ -20,152 +24,6 @@ constexpr float kTransitionStart = 0.65f; constexpr float kTransitionEnd = 0.95f; constexpr float kMinimumVerticalViewComponent = 0.15f; -const char kBuiltinInfiniteGridHlsl[] = R"( -cbuffer GridConstants : register(b0) { - float4x4 gViewProjectionMatrix; - float4 gCameraPositionAndScale; - float4 gCameraRightAndFade; - float4 gCameraUpAndTanHalfFov; - float4 gCameraForwardAndAspect; - float4 gViewportNearFar; - float4 gGridTransition; -}; - -struct VSOutput { - float4 position : SV_POSITION; -}; - -VSOutput MainVS(uint vertexId : SV_VertexID) { - static const float2 positions[3] = { - float2(-1.0, -1.0), - float2(-1.0, 3.0), - float2( 3.0, -1.0) - }; - - VSOutput output; - output.position = float4(positions[vertexId], 0.0, 1.0); - return output; -} - -float PristineGridLine(float2 uv) { - float2 deriv = max(fwidth(uv), float2(1e-6, 1e-6)); - float2 uvMod = frac(uv); - float2 uvDist = min(uvMod, 1.0 - uvMod); - float2 distInPixels = uvDist / deriv; - float2 lineAlpha = 1.0 - smoothstep(0.0, 1.0, distInPixels); - float density = max(deriv.x, deriv.y); - float densityFade = 1.0 - smoothstep(0.5, 1.0, density); - return max(lineAlpha.x, lineAlpha.y) * densityFade; -} - -float AxisLineAA(float coord, float deriv) { - float distInPixels = abs(coord) / max(deriv, 1e-6); - return 1.0 - smoothstep(0.0, 1.5, distInPixels); -} - -struct GridLayer { - float minor; - float major; -}; - -GridLayer SampleGridLayer(float2 worldPos2D, float baseScale) { - GridLayer layer; - const float2 gridCoord1 = worldPos2D / baseScale; - const float2 gridCoord10 = worldPos2D / (baseScale * 10.0); - const float grid1 = PristineGridLine(gridCoord1); - const float grid10 = PristineGridLine(gridCoord10); - const float2 deriv1 = fwidth(gridCoord1); - const float lodFactor = smoothstep(0.3, 0.6, max(deriv1.x, deriv1.y)); - - layer.major = max(grid10, grid1 * 0.35); - layer.minor = grid1 * (1.0 - lodFactor); - return layer; -} - -struct PSOutput { - float4 color : SV_TARGET0; - float depth : SV_Depth; -}; - -PSOutput MainPS(VSOutput input) { - const float2 viewportSize = max(gViewportNearFar.xy, float2(1.0, 1.0)); - const float scale = max(gCameraPositionAndScale.w, 1e-4); - const float fadeDistance = max(gCameraRightAndFade.w, scale * 10.0); - const float tanHalfFov = max(gCameraUpAndTanHalfFov.w, 1e-4); - const float aspect = max(gCameraForwardAndAspect.w, 1e-4); - const float transitionBlend = saturate(gGridTransition.x); - const float nearClip = gViewportNearFar.z; - const float sceneFarClip = gViewportNearFar.w; - - const float2 ndc = float2( - (input.position.x / viewportSize.x) * 2.0 - 1.0, - 1.0 - (input.position.y / viewportSize.y) * 2.0); - - const float3 cameraPosition = gCameraPositionAndScale.xyz; - const float3 rayDirection = normalize( - gCameraForwardAndAspect.xyz + - ndc.x * aspect * tanHalfFov * gCameraRightAndFade.xyz + - ndc.y * tanHalfFov * gCameraUpAndTanHalfFov.xyz); - - if (abs(rayDirection.y) < 1e-5) { - discard; - } - - const float t = -cameraPosition.y / rayDirection.y; - if (t <= nearClip) { - discard; - } - - const float3 worldPosition = cameraPosition + rayDirection * t; - float depth = 0.999999; - if (t < sceneFarClip) { - const float4 clipPosition = mul(gViewProjectionMatrix, float4(worldPosition, 1.0)); - if (clipPosition.w <= 1e-6) { - discard; - } - - depth = clipPosition.z / clipPosition.w; - if (depth <= 0.0 || depth >= 1.0) { - discard; - } - } - - const float radialFade = - 1.0 - smoothstep(fadeDistance * 0.3, fadeDistance, length(worldPosition - cameraPosition)); - const float normalFade = smoothstep(0.0, 0.15, abs(rayDirection.y)); - const float fadeFactor = radialFade * normalFade; - if (fadeFactor < 1e-3) { - discard; - } - - const float2 worldPos2D = worldPosition.xz; - const GridLayer baseLayer = SampleGridLayer(worldPos2D, scale); - const GridLayer nextLayer = SampleGridLayer(worldPos2D, scale * 10.0); - const float minorGridIntensity = lerp(baseLayer.minor, nextLayer.minor, transitionBlend); - const float majorGridIntensity = lerp(baseLayer.major, nextLayer.major, transitionBlend); - float3 finalColor = float3(0.56, 0.56, 0.56); - float finalAlpha = max( - 0.13 * minorGridIntensity * fadeFactor, - 0.28 * majorGridIntensity * fadeFactor); - - const float2 worldDeriv = max(fwidth(worldPos2D), float2(1e-6, 1e-6)); - const float xAxisAlpha = AxisLineAA(worldPos2D.y, worldDeriv.y) * fadeFactor; - const float zAxisAlpha = AxisLineAA(worldPos2D.x, worldDeriv.x) * fadeFactor; - - const float axisAlpha = max(xAxisAlpha, zAxisAlpha); - finalAlpha = max(finalAlpha, 0.34 * saturate(axisAlpha)); - - if (finalAlpha < 1e-3) { - discard; - } - - PSOutput output; - output.color = float4(finalColor, finalAlpha); - output.depth = depth; - return output; -} -)"; - struct GridConstants { Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); Math::Vector4 cameraPositionAndScale = Math::Vector4::Zero(); @@ -176,6 +34,23 @@ struct GridConstants { Math::Vector4 gridTransition = Math::Vector4::Zero(); }; +const Resources::ShaderPass* FindInfiniteGridCompatiblePass( + const Resources::Shader& shader, + Resources::ShaderBackend backend) { + const Resources::ShaderPass* gridPass = shader.FindPass("InfiniteGrid"); + if (gridPass != nullptr && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, gridPass->name, backend)) { + return gridPass; + } + + if (shader.GetPassCount() > 0 && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, shader.GetPasses()[0].name, backend)) { + return &shader.GetPasses()[0]; + } + + return nullptr; +} + float SnapGridSpacing(float targetSpacing) { const float clampedTarget = (std::max)(targetSpacing, 0.02f); const float exponent = std::floor(std::log10(clampedTarget)); @@ -370,6 +245,26 @@ bool BuiltinInfiniteGridPass::CreateResources(const RenderContext& renderContext m_device = renderContext.device; m_backendType = renderContext.backendType; + m_builtinInfiniteGridShader = Resources::ResourceManager::Get().Load( + Resources::GetBuiltinInfiniteGridShaderPath()); + if (!m_builtinInfiniteGridShader.IsValid()) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinInfiniteGridPass failed to load builtin infinite-grid shader resource"); + DestroyResources(); + return false; + } + + const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType); + const Resources::ShaderPass* infiniteGridPass = + FindInfiniteGridCompatiblePass(*m_builtinInfiniteGridShader.Get(), backend); + if (infiniteGridPass == nullptr) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinInfiniteGridPass could not resolve a valid InfiniteGrid shader pass"); + DestroyResources(); + return false; + } RHI::DescriptorSetLayoutBinding constantBinding = {}; constantBinding.binding = 0; @@ -431,19 +326,18 @@ bool BuiltinInfiniteGridPass::CreateResources(const RenderContext& renderContext pipelineDesc.depthStencilState.depthWriteEnable = false; pipelineDesc.depthStencilState.depthFunc = static_cast(RHI::ComparisonFunc::LessEqual); - pipelineDesc.vertexShader.source.assign( - kBuiltinInfiniteGridHlsl, - kBuiltinInfiniteGridHlsl + std::strlen(kBuiltinInfiniteGridHlsl)); - pipelineDesc.vertexShader.sourceLanguage = RHI::ShaderLanguage::HLSL; - pipelineDesc.vertexShader.entryPoint = L"MainVS"; - pipelineDesc.vertexShader.profile = L"vs_5_0"; - - pipelineDesc.fragmentShader.source.assign( - kBuiltinInfiniteGridHlsl, - kBuiltinInfiniteGridHlsl + std::strlen(kBuiltinInfiniteGridHlsl)); - pipelineDesc.fragmentShader.sourceLanguage = RHI::ShaderLanguage::HLSL; - pipelineDesc.fragmentShader.entryPoint = L"MainPS"; - pipelineDesc.fragmentShader.profile = L"ps_5_0"; + if (const Resources::ShaderStageVariant* vertexVariant = m_builtinInfiniteGridShader->FindVariant( + infiniteGridPass->name, + Resources::ShaderType::Vertex, + backend)) { + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*vertexVariant, pipelineDesc.vertexShader); + } + if (const Resources::ShaderStageVariant* fragmentVariant = m_builtinInfiniteGridShader->FindVariant( + infiniteGridPass->name, + Resources::ShaderType::Fragment, + backend)) { + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*fragmentVariant, pipelineDesc.fragmentShader); + } m_pipelineState = m_device->CreatePipelineState(pipelineDesc); if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) { @@ -481,6 +375,7 @@ void BuiltinInfiniteGridPass::DestroyResources() { m_device = nullptr; m_backendType = RHI::RHIType::D3D12; + m_builtinInfiniteGridShader.Reset(); } } // namespace Passes diff --git a/engine/src/Resources/BuiltinResources.cpp b/engine/src/Resources/BuiltinResources.cpp index 89851334..0199c297 100644 --- a/engine/src/Resources/BuiltinResources.cpp +++ b/engine/src/Resources/BuiltinResources.cpp @@ -26,6 +26,7 @@ constexpr const char* kBuiltinTexturePrefix = "builtin://textures/"; constexpr const char* kBuiltinDefaultPrimitiveMaterialPath = "builtin://materials/default-primitive"; constexpr const char* kBuiltinForwardLitShaderPath = "builtin://shaders/forward-lit"; constexpr const char* kBuiltinObjectIdShaderPath = "builtin://shaders/object-id"; +constexpr const char* kBuiltinInfiniteGridShaderPath = "builtin://shaders/infinite-grid"; constexpr const char* kBuiltinDefaultPrimitiveTexturePath = "builtin://textures/default-primitive-albedo"; constexpr float kPi = 3.14159265358979323846f; @@ -308,6 +309,152 @@ void main() { } )"; +const char kBuiltinInfiniteGridHlsl[] = R"( +cbuffer GridConstants : register(b0) { + float4x4 gViewProjectionMatrix; + float4 gCameraPositionAndScale; + float4 gCameraRightAndFade; + float4 gCameraUpAndTanHalfFov; + float4 gCameraForwardAndAspect; + float4 gViewportNearFar; + float4 gGridTransition; +}; + +struct VSOutput { + float4 position : SV_POSITION; +}; + +VSOutput MainVS(uint vertexId : SV_VertexID) { + static const float2 positions[3] = { + float2(-1.0, -1.0), + float2(-1.0, 3.0), + float2( 3.0, -1.0) + }; + + VSOutput output; + output.position = float4(positions[vertexId], 0.0, 1.0); + return output; +} + +float PristineGridLine(float2 uv) { + float2 deriv = max(fwidth(uv), float2(1e-6, 1e-6)); + float2 uvMod = frac(uv); + float2 uvDist = min(uvMod, 1.0 - uvMod); + float2 distInPixels = uvDist / deriv; + float2 lineAlpha = 1.0 - smoothstep(0.0, 1.0, distInPixels); + float density = max(deriv.x, deriv.y); + float densityFade = 1.0 - smoothstep(0.5, 1.0, density); + return max(lineAlpha.x, lineAlpha.y) * densityFade; +} + +float AxisLineAA(float coord, float deriv) { + float distInPixels = abs(coord) / max(deriv, 1e-6); + return 1.0 - smoothstep(0.0, 1.5, distInPixels); +} + +struct GridLayer { + float minor; + float major; +}; + +GridLayer SampleGridLayer(float2 worldPos2D, float baseScale) { + GridLayer layer; + const float2 gridCoord1 = worldPos2D / baseScale; + const float2 gridCoord10 = worldPos2D / (baseScale * 10.0); + const float grid1 = PristineGridLine(gridCoord1); + const float grid10 = PristineGridLine(gridCoord10); + const float2 deriv1 = fwidth(gridCoord1); + const float lodFactor = smoothstep(0.3, 0.6, max(deriv1.x, deriv1.y)); + + layer.major = max(grid10, grid1 * 0.35); + layer.minor = grid1 * (1.0 - lodFactor); + return layer; +} + +struct PSOutput { + float4 color : SV_TARGET0; + float depth : SV_Depth; +}; + +PSOutput MainPS(VSOutput input) { + const float2 viewportSize = max(gViewportNearFar.xy, float2(1.0, 1.0)); + const float scale = max(gCameraPositionAndScale.w, 1e-4); + const float fadeDistance = max(gCameraRightAndFade.w, scale * 10.0); + const float tanHalfFov = max(gCameraUpAndTanHalfFov.w, 1e-4); + const float aspect = max(gCameraForwardAndAspect.w, 1e-4); + const float transitionBlend = saturate(gGridTransition.x); + const float nearClip = gViewportNearFar.z; + const float sceneFarClip = gViewportNearFar.w; + + const float2 ndc = float2( + (input.position.x / viewportSize.x) * 2.0 - 1.0, + 1.0 - (input.position.y / viewportSize.y) * 2.0); + + const float3 cameraPosition = gCameraPositionAndScale.xyz; + const float3 rayDirection = normalize( + gCameraForwardAndAspect.xyz + + ndc.x * aspect * tanHalfFov * gCameraRightAndFade.xyz + + ndc.y * tanHalfFov * gCameraUpAndTanHalfFov.xyz); + + if (abs(rayDirection.y) < 1e-5) { + discard; + } + + const float t = -cameraPosition.y / rayDirection.y; + if (t <= nearClip) { + discard; + } + + const float3 worldPosition = cameraPosition + rayDirection * t; + float depth = 0.999999; + if (t < sceneFarClip) { + const float4 clipPosition = mul(gViewProjectionMatrix, float4(worldPosition, 1.0)); + if (clipPosition.w <= 1e-6) { + discard; + } + + depth = clipPosition.z / clipPosition.w; + if (depth <= 0.0 || depth >= 1.0) { + discard; + } + } + + const float radialFade = + 1.0 - smoothstep(fadeDistance * 0.3, fadeDistance, length(worldPosition - cameraPosition)); + const float normalFade = smoothstep(0.0, 0.15, abs(rayDirection.y)); + const float fadeFactor = radialFade * normalFade; + if (fadeFactor < 1e-3) { + discard; + } + + const float2 worldPos2D = worldPosition.xz; + const GridLayer baseLayer = SampleGridLayer(worldPos2D, scale); + const GridLayer nextLayer = SampleGridLayer(worldPos2D, scale * 10.0); + const float minorGridIntensity = lerp(baseLayer.minor, nextLayer.minor, transitionBlend); + const float majorGridIntensity = lerp(baseLayer.major, nextLayer.major, transitionBlend); + float3 finalColor = float3(0.56, 0.56, 0.56); + float finalAlpha = max( + 0.13 * minorGridIntensity * fadeFactor, + 0.28 * majorGridIntensity * fadeFactor); + + const float2 worldDeriv = max(fwidth(worldPos2D), float2(1e-6, 1e-6)); + const float xAxisAlpha = AxisLineAA(worldPos2D.y, worldDeriv.y) * fadeFactor; + const float zAxisAlpha = AxisLineAA(worldPos2D.x, worldDeriv.x) * fadeFactor; + + const float axisAlpha = max(xAxisAlpha, zAxisAlpha); + finalAlpha = max(finalAlpha, 0.34 * saturate(axisAlpha)); + + if (finalAlpha < 1e-3) { + discard; + } + + PSOutput output; + output.color = float4(finalColor, finalAlpha); + output.depth = depth; + return output; +} +)"; + Math::Bounds ComputeBounds(const std::vector& vertices) { if (vertices.empty()) { return Math::Bounds(); @@ -943,6 +1090,41 @@ Shader* BuildBuiltinObjectIdShader(const Containers::String& path) { return shader; } +Shader* BuildBuiltinInfiniteGridShader(const Containers::String& path) { + auto* shader = new Shader(); + IResource::ConstructParams params; + params.name = Containers::String("Builtin Infinite Grid"); + params.path = path; + params.guid = ResourceGUID::Generate(path); + params.memorySize = 0; + shader->Initialize(params); + + const Containers::String passName("InfiniteGrid"); + shader->SetPassTag(passName, "LightMode", "InfiniteGrid"); + + AddBuiltinShaderStageVariant( + *shader, + passName, + ShaderType::Vertex, + ShaderLanguage::HLSL, + ShaderBackend::D3D12, + kBuiltinInfiniteGridHlsl, + "MainVS", + "vs_5_0"); + AddBuiltinShaderStageVariant( + *shader, + passName, + ShaderType::Fragment, + ShaderLanguage::HLSL, + ShaderBackend::D3D12, + kBuiltinInfiniteGridHlsl, + "MainPS", + "ps_5_0"); + + shader->m_memorySize = CalculateBuiltinShaderMemorySize(*shader); + return shader; +} + Material* BuildDefaultPrimitiveMaterial(const Containers::String& path) { auto* material = new Material(); IResource::ConstructParams params; @@ -1049,6 +1231,10 @@ Containers::String GetBuiltinObjectIdShaderPath() { return Containers::String(kBuiltinObjectIdShaderPath); } +Containers::String GetBuiltinInfiniteGridShaderPath() { + return Containers::String(kBuiltinInfiniteGridShaderPath); +} + Containers::String GetBuiltinDefaultPrimitiveTexturePath() { return Containers::String(kBuiltinDefaultPrimitiveTexturePath); } @@ -1141,6 +1327,8 @@ LoadResult CreateBuiltinShaderResource(const Containers::String& path) { shader = BuildBuiltinForwardLitShader(path); } else if (path == GetBuiltinObjectIdShaderPath()) { shader = BuildBuiltinObjectIdShader(path); + } else if (path == GetBuiltinInfiniteGridShaderPath()) { + shader = BuildBuiltinInfiniteGridShader(path); } else { return LoadResult(Containers::String("Unknown builtin shader: ") + path); } diff --git a/tests/Resources/Shader/test_shader_loader.cpp b/tests/Resources/Shader/test_shader_loader.cpp index 1fd92f77..018d6713 100644 --- a/tests/Resources/Shader/test_shader_loader.cpp +++ b/tests/Resources/Shader/test_shader_loader.cpp @@ -33,6 +33,7 @@ TEST(ShaderLoader, CanLoad) { EXPECT_TRUE(loader.CanLoad("test.hlsl")); EXPECT_TRUE(loader.CanLoad(GetBuiltinForwardLitShaderPath())); EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdShaderPath())); + EXPECT_TRUE(loader.CanLoad(GetBuiltinInfiniteGridShaderPath())); EXPECT_FALSE(loader.CanLoad("test.txt")); EXPECT_FALSE(loader.CanLoad("test.png")); } @@ -128,6 +129,31 @@ TEST(ShaderLoader, LoadBuiltinObjectIdShaderBuildsBackendVariants) { delete shader; } +TEST(ShaderLoader, LoadBuiltinInfiniteGridShaderBuildsD3D12Variants) { + ShaderLoader loader; + LoadResult result = loader.Load(GetBuiltinInfiniteGridShaderPath()); + 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("InfiniteGrid"); + ASSERT_NE(pass, nullptr); + ASSERT_EQ(pass->variants.Size(), 2u); + ASSERT_EQ(pass->tags.Size(), 1u); + EXPECT_EQ(pass->tags[0].name, "LightMode"); + EXPECT_EQ(pass->tags[0].value, "InfiniteGrid"); + + EXPECT_NE(shader->FindVariant("InfiniteGrid", ShaderType::Vertex, ShaderBackend::D3D12), nullptr); + EXPECT_NE(shader->FindVariant("InfiniteGrid", ShaderType::Fragment, ShaderBackend::D3D12), nullptr); + EXPECT_EQ(shader->FindVariant("InfiniteGrid", ShaderType::Vertex, ShaderBackend::OpenGL), nullptr); + EXPECT_EQ(shader->FindVariant("InfiniteGrid", ShaderType::Fragment, ShaderBackend::OpenGL), nullptr); + + delete shader; +} + TEST(ShaderLoader, ResourceManagerLazilyLoadsBuiltinForwardLitShader) { ResourceManager& manager = ResourceManager::Get(); manager.Shutdown(); @@ -141,6 +167,10 @@ TEST(ShaderLoader, ResourceManagerLazilyLoadsBuiltinForwardLitShader) { ASSERT_TRUE(objectIdShaderHandle.IsValid()); ASSERT_NE(objectIdShaderHandle->FindPass("ObjectId"), nullptr); + ResourceHandle infiniteGridShaderHandle = manager.Load(GetBuiltinInfiniteGridShaderPath()); + ASSERT_TRUE(infiniteGridShaderHandle.IsValid()); + ASSERT_NE(infiniteGridShaderHandle->FindPass("InfiniteGrid"), nullptr); + manager.Shutdown(); }