From 0320764b148dc73d6c5143323cf1bdde048d983f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 6 Nov 2023 19:33:31 -0800 Subject: [PATCH 1/3] bugfix: remove parllax from pre/post z pass Signed-off-by: Michael Pollind --- HPL2/include/graphics/RendererDeferred.h | 1 + HPL2/resource/ShaderList.fsl | 12 ++++- HPL2/resource/pbr.h.fsl | 17 +++++++ HPL2/resource/solid_diffuse.frag.fsl | 32 +++++++++++- HPL2/resource/solid_z.frag.fsl | 57 ---------------------- HPL2/resource/solid_z.vert.fsl | 28 +++++------ HPL2/resource/solid_z_cut.vert.fsl | 30 ++++++++++++ HPL2/resource/solid_z_shadow.frag.fsl | 56 +++++++++++++++++++++ HPL2/resource/solid_z_shadow.vert.fsl | 28 +++++++++++ HPL2/sources/graphics/RendererDeferred.cpp | 55 ++++++++++++--------- 10 files changed, 220 insertions(+), 96 deletions(-) create mode 100644 HPL2/resource/pbr.h.fsl create mode 100644 HPL2/resource/solid_z_cut.vert.fsl create mode 100644 HPL2/resource/solid_z_shadow.frag.fsl create mode 100644 HPL2/resource/solid_z_shadow.vert.fsl diff --git a/HPL2/include/graphics/RendererDeferred.h b/HPL2/include/graphics/RendererDeferred.h index 352138452..6d11c4d1c 100644 --- a/HPL2/include/graphics/RendererDeferred.h +++ b/HPL2/include/graphics/RendererDeferred.h @@ -597,6 +597,7 @@ namespace hpl { std::array, ForgeRenderer::SwapChainLength> m_lightResources{}; // z pass SharedShader m_zPassShader; + SharedShader m_zPassShadowShader; SharedPipeline m_zPassPipelineCCW; SharedPipeline m_zPassPipelineCW; diff --git a/HPL2/resource/ShaderList.fsl b/HPL2/resource/ShaderList.fsl index c7c365a84..f8a077aa7 100644 --- a/HPL2/resource/ShaderList.fsl +++ b/HPL2/resource/ShaderList.fsl @@ -1,11 +1,19 @@ /// Copyright © 2009-2020 Frictional Games /// Copyright 2023 Michael Pollind /// SPDX-License-Identifier: GPL-3.0 - -#vert solid_z.vert +#vert solid_z_shadow.vert #include "solid_z.vert.fsl" #end +#frag solid_z_shadow.frag + #define ALPHA_REJECT 0.5 + #include "solid_z_shadow.frag.fsl" +#end + +#vert solid_z_shadow.vert + #include "solid_z_shadow.vert.fsl" +#end + #frag solid_z.frag #define SEARCH_SAMPLE_COUNT 4 #define PARALLAX_ENABLED 1 diff --git a/HPL2/resource/pbr.h.fsl b/HPL2/resource/pbr.h.fsl new file mode 100644 index 000000000..7e7b5e658 --- /dev/null +++ b/HPL2/resource/pbr.h.fsl @@ -0,0 +1,17 @@ +// https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf +// +float3 F_Schlick (float3 f0 , float f90 , float u ){ + return f0 + ( f90 - f0 ) * pow (1. f - u , 5. f ) ; +} + +float Fr_DisneyDiffuse(float NdotV ,float NdotL ,float LdotH ,float linearRoughness) +{ + float energyBias = lerp (0 , 0.5 , linearRoughness ) ; + float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness ) ; + float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ; + float3 f0 = float3 (1.0 f , 1.0 f , 1.0 f ) ; + float lightScatter = F_Schlick ( f0 , fd90 , NdotL ) * r ; + float viewScatter = F_Schlick ( f0 , fd90 , NdotV ) * r ; + + return lightScatter * viewScatter * energyFactor ; +} diff --git a/HPL2/resource/solid_diffuse.frag.fsl b/HPL2/resource/solid_diffuse.frag.fsl index b54a34054..416cf026d 100644 --- a/HPL2/resource/solid_diffuse.frag.fsl +++ b/HPL2/resource/solid_diffuse.frag.fsl @@ -43,8 +43,38 @@ PsOut PS_MAIN(PsIn In) } #endif + float diffuseAlpha; + if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; + } else { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; + } + } else { + diffuseAlpha = 1.0; + } + + const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; + + if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. + float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; + + if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + //Get in 0.75 - 1 range + fDissolve = fDissolve*0.25 + 0.75; + + float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; + fDissolve -= (0.25 - fDissolveAlpha * 0.25); + } else { + //Get in 0.5 - 1 range. + fDissolve = fDissolve*0.5 + 0.5; + } + diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; + } + float4 diffuseColor = SampleTex2D(Get(diffuseMap), Get(materialSampler), texCoord.xy); - if(diffuseColor.w < ALPHA_REJECT ) { + if(diffuseColor.w < ALPHA_REJECT || diffuseAlpha < ALPHA_REJECT) { discard; } diff --git a/HPL2/resource/solid_z.frag.fsl b/HPL2/resource/solid_z.frag.fsl index 8dd45d547..ca6b482b2 100644 --- a/HPL2/resource/solid_z.frag.fsl +++ b/HPL2/resource/solid_z.frag.fsl @@ -8,67 +8,10 @@ STRUCT(PsIn) { DATA(float4, Position, SV_Position); - DATA(float3, pos, POSITION); - DATA(float2, uv, TEXCOORD0); - DATA(float3, normal, NORMAL); - DATA(float3, tangent, TANGENT); - DATA(float3, bitangent, BITANGENT); }; float4 PS_MAIN(PsIn In) { INIT_MAIN; - float2 texCoord = In.uv.xy; - uint materialID = Get(uniformObjectBuffer)[Get(objectId)].materialID; - - #ifdef PARALLAX_ENABLED - if(HasHeight(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - texCoord.xy += ParallaxAdvance(texCoord, - 0.0, - 8.0, - Get(uniformMaterialBuffer)[materialID].heightMapScale * PARALLAX_MULTIPLIER, - In.pos, - In.normal, - In.tangent, - In.bitangent, - IsHeightMapSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)); - } - #endif - - float diffuseAlpha; - if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; - } else { - diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; - } - } else { - diffuseAlpha = 1.0; - } - - const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; - - if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. - float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; - - if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { - //Get in 0.75 - 1 range - fDissolve = fDissolve*0.25 + 0.75; - - float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; - fDissolve -= (0.25 - fDissolveAlpha * 0.25); - } else { - //Get in 0.5 - 1 range. - fDissolve = fDissolve*0.5 + 0.5; - } - diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; - } - - - if(diffuseAlpha < ALPHA_REJECT) { - discard; - } - RETURN(float4(0,0,0,0)); } diff --git a/HPL2/resource/solid_z.vert.fsl b/HPL2/resource/solid_z.vert.fsl index b38064b70..9bf8213ef 100644 --- a/HPL2/resource/solid_z.vert.fsl +++ b/HPL2/resource/solid_z.vert.fsl @@ -5,19 +5,19 @@ STRUCT(VSInput) { DATA(float3, Position, POSITION); - DATA(float2, TexCoord, TEXCOORD0); - DATA(float3, Normal, NORMAL); - DATA(float3, Tangent, TANGENT); + // DATA(float2, TexCoord, TEXCOORD0); + // DATA(float3, Normal, NORMAL); + // DATA(float3, Tangent, TANGENT); }; STRUCT(VSOutput) { DATA(float4, Position, SV_Position); - DATA(float3, pos, POSITION); - DATA(float2, uv, TEXCOORD0); - DATA(float3, normal, NORMAL); - DATA(float3, tangent, TANGENT); - DATA(float3, bitangent, BITANGENT); + // DATA(float3, pos, POSITION); + // DATA(float2, uv, TEXCOORD0); + // DATA(float3, normal, NORMAL); + // DATA(float3, tangent, TANGENT); + // DATA(float3, bitangent, BITANGENT); }; VSOutput VS_MAIN(VSInput In) @@ -28,14 +28,14 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); float4x4 modelViewPrj = mul(Get(projMat), modelView); - Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; +// Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; Out.Position = mul(modelViewPrj , float4(In.Position.xyz, 1.0)); - Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + // Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; - float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); - Out.normal = normalize(mul(normalMat, In.Normal.xyz)); - Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); - Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); + // float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); + // Out.normal = normalize(mul(normalMat, In.Normal.xyz)); + // Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); + // Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); RETURN(Out); } diff --git a/HPL2/resource/solid_z_cut.vert.fsl b/HPL2/resource/solid_z_cut.vert.fsl new file mode 100644 index 000000000..618dc7a05 --- /dev/null +++ b/HPL2/resource/solid_z_cut.vert.fsl @@ -0,0 +1,30 @@ +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(VSInput) +{ + DATA(float3, Position, POSITION); + DATA(float2, TexCoord, TEXCOORD0); +}; + +STRUCT(VSOutput) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); +}; + +VSOutput VS_MAIN(VSInput In) +{ + INIT_MAIN; + VSOutput Out; + + float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); + float4x4 modelViewPrj = mul(Get(projMat), modelView); + + Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + + RETURN(Out); +} diff --git a/HPL2/resource/solid_z_shadow.frag.fsl b/HPL2/resource/solid_z_shadow.frag.fsl new file mode 100644 index 000000000..21b56b788 --- /dev/null +++ b/HPL2/resource/solid_z_shadow.frag.fsl @@ -0,0 +1,56 @@ +/// Copyright © 2009-2020 Frictional Games +/// Copyright 2023 Michael Pollind +/// SPDX-License-Identifier: GPL-3.0 +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(PsIn) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); +}; + +float4 PS_MAIN(PsIn In) +{ + INIT_MAIN; + float2 texCoord = In.uv.xy; + uint materialID = Get(uniformObjectBuffer)[Get(objectId)].materialID; + float diffuseAlpha; + if(HasAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + if(IsAlphaSingleChannel(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).r; + } else { + diffuseAlpha = SampleTex2D(Get(alphaMap), Get(materialSampler), texCoord.xy).a; + } + } else { + diffuseAlpha = 1.0; + } + + const float dissolveAmount = Get(uniformObjectBuffer)[Get(objectId)].dissolveAmount; + + if(dissolveAmount < 1.0 || HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig) || HasDissolveFilter(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + float2 vDissolveCoords = In.Position.xy * (1.0/128.0); //128 = size of dissolve texture. + float fDissolve = SampleTex2D(dissolveMap, Get(dissolveSampler), vDissolveCoords).x; + + if(HasDissolveAlpha(Get(uniformMaterialBuffer)[materialID].materialConfig)) { + //Get in 0.75 - 1 range + fDissolve = fDissolve*0.25 + 0.75; + + float fDissolveAlpha = SampleTex2D(Get(dissolveAlphaMap), Get(materialSampler), texCoord.xy).r; + fDissolve -= (0.25 - fDissolveAlpha * 0.25); + } else { + //Get in 0.5 - 1 range. + fDissolve = fDissolve*0.5 + 0.5; + } + diffuseAlpha = fDissolve - (1.0 - (dissolveAmount * diffuseAlpha)) * 0.5; + } + + + if(diffuseAlpha < ALPHA_REJECT) { + discard; + } + + RETURN(float4(0,0,0,0)); +} diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl new file mode 100644 index 000000000..c95ad3249 --- /dev/null +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -0,0 +1,28 @@ +#define MATERIAL_SOLID 1 +#include "deferred_resources.h.fsl" +#include "deferred_common.h.fsl" + +STRUCT(VSInput) +{ + DATA(float3, Position, POSITION); + DATA(float2, TexCoord, TEXCOORD0); +}; + +STRUCT(VSOutput) +{ + DATA(float4, Position, SV_Position); + DATA(float3, pos, POSITION); +}; + +VSOutput VS_MAIN(VSInput In) +{ + INIT_MAIN; + VSOutput Out; + + float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); + float4x4 modelViewPrj = mul(Get(projMat), modelView); + + Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; + RETURN(Out); +} diff --git a/HPL2/sources/graphics/RendererDeferred.cpp b/HPL2/sources/graphics/RendererDeferred.cpp index b414e075d..b95291716 100644 --- a/HPL2/sources/graphics/RendererDeferred.cpp +++ b/HPL2/sources/graphics/RendererDeferred.cpp @@ -187,14 +187,10 @@ namespace hpl { } } - //////////////////////// - // Iterate children for (auto& childNode : apNode->GetChildNodes()) { walkShadowCasters(childNode, frustumCollision); } - ///////////////////////////// - // Iterate objects for (auto& object : apNode->GetObjects()) { // Check so visible and shadow caster if (rendering::detail::IsObjectIsVisible(object, eRenderableFlag_ShadowCaster, clipPlanes) == false || @@ -1133,6 +1129,13 @@ namespace hpl { //---------------- Diffuse Pipeline ------------------------ { // z pass + m_zPassShadowShader.Load(forgeRenderer->Rend(), [&](Shader** shader) { + ShaderLoadDesc loadDesc = {}; + loadDesc.mStages[0].pFileName = "solid_z_shadow.vert"; + loadDesc.mStages[1].pFileName = "solid_z_shadow.frag"; + addShader(forgeRenderer->Rend(), &loadDesc, shader); + return true; + }); m_zPassShader.Load(forgeRenderer->Rend(), [&](Shader** shader) { ShaderLoadDesc loadDesc = {}; loadDesc.mStages[0].pFileName = "solid_z.vert"; @@ -1301,8 +1304,8 @@ namespace hpl { DepthStateDesc depthStateDesc = {}; depthStateDesc.mDepthTest = true; - depthStateDesc.mDepthWrite = false; - depthStateDesc.mDepthFunc = CMP_EQUAL; + depthStateDesc.mDepthWrite = true; + depthStateDesc.mDepthFunc = CMP_LEQUAL; std::array colorFormats = { ColorBufferFormat, NormalBufferFormat, PositionBufferFormat, SpecularBufferFormat }; @@ -1537,7 +1540,7 @@ namespace hpl { pipelineSettings.mDepthStencilFormat = ShadowDepthBufferFormat; pipelineSettings.mSampleQuality = 0; pipelineSettings.pRootSignature = m_materialRootSignature.m_handle; - pipelineSettings.pShaderProgram = m_zPassShader.m_handle; + pipelineSettings.pShaderProgram = m_zPassShadowShader.m_handle; pipelineSettings.pRasterizerState = &rasterizerStateDesc; pipelineSettings.pVertexLayout = &vertexLayout; addPipeline(forgeRenderer->Rend(), &pipelineDesc, pipeline); @@ -1564,7 +1567,7 @@ namespace hpl { pipelineSettings.mDepthStencilFormat = ShadowDepthBufferFormat; pipelineSettings.mSampleQuality = 0; pipelineSettings.pRootSignature = m_materialRootSignature.m_handle; - pipelineSettings.pShaderProgram = m_zPassShader.m_handle; + pipelineSettings.pShaderProgram = m_zPassShadowShader.m_handle; pipelineSettings.pRasterizerState = &rasterizerStateDesc; pipelineSettings.pVertexLayout = &vertexLayout; addPipeline(forgeRenderer->Rend(), &pipelineDesc, pipeline); @@ -2760,9 +2763,7 @@ namespace hpl { cMaterial* pMaterial = pObject->GetMaterial(); const ShaderMaterialData& descriptor = pMaterial->Descriptor(); std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + eVertexBufferElement_Texture0 }; DrawPacket packet = pObject->ResolveDrawPacket(frame, targets); if (packet.m_type == DrawPacket::Unknown || descriptor.m_id == MaterialID::Unknown) { return; @@ -3240,6 +3241,23 @@ namespace hpl { ASSERT(depthBuffer && "Depth buffer not created"); ASSERT(hiZBuffer && "Depth buffer not created"); + auto isValidForPreAndPostZ = [](cMaterial* material, iRenderable* renderable ) { + if (!material) { + return false; + } + if(renderable->GetCoverageAmount() < 1.0) { + return false; + } + if(cMaterial::IsTranslucent(material->Descriptor().m_id)) { + return false; + } + if(material->GetImage(eMaterialTexture_Alpha)) { + return false; + } + + return true; + }; + FenceStatus fenceStatus; getFenceStatus(frame.m_renderer->Rend(), m_prePassFence.m_handle, &fenceStatus); if (fenceStatus == FENCE_STATUS_INCOMPLETE) { @@ -3407,14 +3425,11 @@ namespace hpl { reinterpret_cast(updateDesc.pMappedData)[1] = float4(boundBoxMax.x, boundBoxMax.y, boundBoxMax.z, 0.0f); endUpdateResource(&updateDesc, nullptr); - if (!test.m_preZPass || !pMaterial || cMaterial::IsTranslucent(pMaterial->Descriptor().m_id)) { + if (!test.m_preZPass || !isValidForPreAndPostZ(pMaterial, test.m_renderable)) { continue; } - std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + std::array targets = { eVertexBufferElement_Position}; DrawPacket packet = test.m_renderable->ResolveDrawPacket(frame, targets); if (packet.m_type == DrawPacket::Unknown) { continue; @@ -3646,13 +3661,10 @@ namespace hpl { renderable->GetCoverageAmount() >= 1 ? eMaterialRenderMode_Z : eMaterialRenderMode_Z_Dissolve; cMaterial* pMaterial = renderable->GetMaterial(); - if (!pMaterial || cMaterial::IsTranslucent(pMaterial->Descriptor().m_id)) { + if (!isValidForPreAndPostZ(pMaterial, renderable)) { continue; } - std::array targets = { eVertexBufferElement_Position, - eVertexBufferElement_Texture0, - eVertexBufferElement_Normal, - eVertexBufferElement_Texture1Tangent }; + std::array targets = { eVertexBufferElement_Position }; DrawPacket drawPacket = renderable->ResolveDrawPacket(frame, targets); if (drawPacket.m_type == DrawPacket::Unknown) { continue; @@ -3991,7 +4003,6 @@ namespace hpl { // Setup far plane coordinates /////////////////////////// - // Occlusion testing m_rendererList.BeginAndReset(afFrameTime, apFrustum); cmdPreAndPostZ( frame.m_cmd, From bc9feb435501fa5ee0b11b838d660d026d977b3f Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 7 Nov 2023 07:02:06 -0800 Subject: [PATCH 2/3] fix Signed-off-by: Michael Pollind --- HPL2/resource/solid_z.vert.fsl | 15 --------------- HPL2/resource/solid_z_shadow.vert.fsl | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/HPL2/resource/solid_z.vert.fsl b/HPL2/resource/solid_z.vert.fsl index 9bf8213ef..3c7e39f07 100644 --- a/HPL2/resource/solid_z.vert.fsl +++ b/HPL2/resource/solid_z.vert.fsl @@ -5,19 +5,11 @@ STRUCT(VSInput) { DATA(float3, Position, POSITION); - // DATA(float2, TexCoord, TEXCOORD0); - // DATA(float3, Normal, NORMAL); - // DATA(float3, Tangent, TANGENT); }; STRUCT(VSOutput) { DATA(float4, Position, SV_Position); - // DATA(float3, pos, POSITION); - // DATA(float2, uv, TEXCOORD0); - // DATA(float3, normal, NORMAL); - // DATA(float3, tangent, TANGENT); - // DATA(float3, bitangent, BITANGENT); }; VSOutput VS_MAIN(VSInput In) @@ -28,14 +20,7 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelView = mul(Get(viewMat), Get(uniformObjectBuffer)[Get(objectId)].modelMat); float4x4 modelViewPrj = mul(Get(projMat), modelView); -// Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; Out.Position = mul(modelViewPrj , float4(In.Position.xyz, 1.0)); - // Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; - - // float3x3 normalMat = ToNormalMat(Get(uniformObjectBuffer)[Get(objectId)].invModelMat, Get(invViewMat)); - // Out.normal = normalize(mul(normalMat, In.Normal.xyz)); - // Out.tangent = normalize(mul(normalMat, In.Tangent.xyz)); - // Out.bitangent = normalize(mul(normalMat, cross(In.Tangent.xyz, In.Normal.xyz))); RETURN(Out); } diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl index c95ad3249..b480e68e3 100644 --- a/HPL2/resource/solid_z_shadow.vert.fsl +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -12,6 +12,7 @@ STRUCT(VSOutput) { DATA(float4, Position, SV_Position); DATA(float3, pos, POSITION); + DATA(float2, uv, TEXCOORD0); }; VSOutput VS_MAIN(VSInput In) From 47db28e09ead77d15540b03a27f0aab452be48c2 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 7 Nov 2023 20:56:51 -0800 Subject: [PATCH 3/3] feat: add shadow cache implementation Signed-off-by: Michael Pollind --- HPL2/include/graphics/IndexPool.h | 2 + HPL2/include/graphics/RendererDeferred.h | 2 + HPL2/include/graphics/ShadowCache.h | 69 ++++++++ HPL2/resource/solid_z_shadow.vert.fsl | 1 + HPL2/sources/graphics/IndexPool.cpp | 3 +- HPL2/sources/graphics/RendererDeferred.cpp | 3 +- HPL2/sources/graphics/ShadowCache.cpp | 192 +++++++++++++++++++++ 7 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 HPL2/include/graphics/ShadowCache.h create mode 100644 HPL2/sources/graphics/ShadowCache.cpp diff --git a/HPL2/include/graphics/IndexPool.h b/HPL2/include/graphics/IndexPool.h index ae63a6f51..f8762b499 100644 --- a/HPL2/include/graphics/IndexPool.h +++ b/HPL2/include/graphics/IndexPool.h @@ -14,12 +14,14 @@ namespace hpl { IndexPool(uint32_t reserve); uint32_t requestId(); + inline uint32_t reserve() {return m_reserve;} void returnId(uint32_t); private: struct IdRange { uint32_t m_start; uint32_t m_end; }; + uint32_t m_reserve; folly::small_vector m_avaliable; }; diff --git a/HPL2/include/graphics/RendererDeferred.h b/HPL2/include/graphics/RendererDeferred.h index 6d11c4d1c..01a08a45d 100644 --- a/HPL2/include/graphics/RendererDeferred.h +++ b/HPL2/include/graphics/RendererDeferred.h @@ -20,6 +20,7 @@ #include "engine/RTTI.h" +#include "graphics/ShadowCache.h" #include "scene/Viewport.h" #include "scene/World.h" #include "windowing/NativeWindow.h" @@ -708,5 +709,6 @@ namespace hpl { cRenderList m_reflectionRendererList; std::unique_ptr m_hbaoPlusPipeline; std::shared_ptr m_debug; + ShadowCache m_shadowCache; }; }; // namespace hpl diff --git a/HPL2/include/graphics/ShadowCache.h b/HPL2/include/graphics/ShadowCache.h new file mode 100644 index 000000000..f3f196635 --- /dev/null +++ b/HPL2/include/graphics/ShadowCache.h @@ -0,0 +1,69 @@ +#pragma once + +#include "graphics/IndexPool.h" +#include +#include + +#include + +#include +#include +#include + + +namespace hpl { + class ShadowCache { + public: + + struct ShadowGroup { + public: + static constexpr uint8_t IsLeaf = 0x1; + static constexpr uint8_t HasLeafs = 0x2; + static constexpr uint8_t HasGroups = 0x4; + + uint16_t m_idx; + + uint16_t m_x; + uint16_t m_y; + uint32_t m_age; + + uint16_t m_parent; // the parent of the cache entry + uint16_t m_child; // the start of the group + + // linked list for all cut levels at the same cut + uint16_t m_next; + uint16_t m_prev; + + uint8_t m_flags; + uint8_t m_occupyMask: 4; // mask for the entires occuped + uint8_t m_slot: 4; // the slot index + uint8_t m_level; + + uint16_t m_hashes[4]; + }; + + + struct CutLevel { + uint16_t m_begin = UINT16_MAX; + }; + + ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts); + void reset(uint32_t age); + uint4 find(uint16_t hash, uint8_t level, uint32_t age); + private: + ShadowGroup* allocGroup(); + ShadowCache::ShadowGroup* createCut(ShadowGroup* group); + + void freeGroup(ShadowGroup* group); + void freeChildren(ShadowGroup* group); + + void updateAge(ShadowCache::ShadowGroup* current, uint32_t age); + void insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); + void insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp); + + uint2 m_quadSize; + hpl::IndexPool m_pool; + std::vector m_alloc; // a reserved pool of entries will contain the max possible i.e all the quads are at its lowest cut + std::vector m_cut; // cut levels for each quad + }; +} diff --git a/HPL2/resource/solid_z_shadow.vert.fsl b/HPL2/resource/solid_z_shadow.vert.fsl index b480e68e3..870795ddc 100644 --- a/HPL2/resource/solid_z_shadow.vert.fsl +++ b/HPL2/resource/solid_z_shadow.vert.fsl @@ -24,6 +24,7 @@ VSOutput VS_MAIN(VSInput In) float4x4 modelViewPrj = mul(Get(projMat), modelView); Out.uv = mul(Get(uniformObjectBuffer)[Get(objectId)].uvMat, float4(In.TexCoord, 0, 1.0)).xy; + Out.Position = mul(modelViewPrj, float4(In.Position.xyz, 1.0)); Out.pos = mul(modelView, float4(In.Position.xyz, 1.0)).xyz; RETURN(Out); } diff --git a/HPL2/sources/graphics/IndexPool.cpp b/HPL2/sources/graphics/IndexPool.cpp index a4a0a7cf7..6a27eadb2 100644 --- a/HPL2/sources/graphics/IndexPool.cpp +++ b/HPL2/sources/graphics/IndexPool.cpp @@ -7,7 +7,8 @@ namespace hpl { - IndexPool::IndexPool(uint32_t reserve) { + IndexPool::IndexPool(uint32_t reserve): + m_reserve(reserve) { m_avaliable.push_back({0, reserve - 1}); } diff --git a/HPL2/sources/graphics/RendererDeferred.cpp b/HPL2/sources/graphics/RendererDeferred.cpp index b95291716..cd37bdfd6 100644 --- a/HPL2/sources/graphics/RendererDeferred.cpp +++ b/HPL2/sources/graphics/RendererDeferred.cpp @@ -508,7 +508,8 @@ namespace hpl { cRendererDeferred::cRendererDeferred(cGraphics* apGraphics, cResources* apResources, std::shared_ptr debug) : iRenderer("Deferred", apGraphics, apResources) - , m_debug(debug) { + , m_debug(debug) + , m_shadowCache(8192, 4096, 8, 4, 3) { m_hbaoPlusPipeline = std::make_unique(); //////////////////////////////////// // Set up render specific things diff --git a/HPL2/sources/graphics/ShadowCache.cpp b/HPL2/sources/graphics/ShadowCache.cpp new file mode 100644 index 000000000..3dc8717af --- /dev/null +++ b/HPL2/sources/graphics/ShadowCache.cpp @@ -0,0 +1,192 @@ +#include "graphics/ShadowCache.h" +#include "graphics/IndexPool.h" +#include +#include +#include + +namespace hpl { + + void ShadowCache::insertAfter(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { + ASSERT(current); + ASSERT(grp); + uint16_t nextIdx = current->m_next; + + current->m_next = grp->m_idx; + grp->m_prev = current->m_idx; + + grp->m_next = nextIdx; + if(nextIdx != UINT16_MAX) { + m_alloc[nextIdx].m_prev = grp->m_idx; + } + } + void ShadowCache::insertBefore(ShadowCache::ShadowGroup* current, ShadowCache::ShadowGroup* grp) { + ASSERT(current); + ASSERT(grp); + uint16_t prevIdx = current->m_prev; + + current->m_prev = grp->m_idx; + grp->m_next = current->m_idx; + + grp->m_prev = prevIdx; + if(prevIdx != UINT16_MAX) { + m_alloc[prevIdx].m_next = grp->m_idx; + } + } + ShadowCache::ShadowCache(uint32_t width, uint32_t height, uint32_t hDivisions, uint32_t vDivision, uint8_t maxCuts): + m_quadSize(width/vDivision, height/ hDivisions), + m_pool((std::pow(std::max(1, (static_cast(maxCuts) - 2)), 4) + 1) * hDivisions * vDivision) { + ASSERT(m_pool.reserve() > std::numeric_limits::max()); + m_alloc.resize(m_pool.reserve()); + m_cut.resize(maxCuts); + ShadowCache::ShadowGroup* previous = nullptr; + for(size_t x = 0; x < hDivisions; x++) { + for(size_t y = 0; y < vDivision; y++) { + ShadowCache::ShadowGroup* entry = allocGroup(); + entry->m_x = m_quadSize.x * x; + entry->m_y = m_quadSize.y * y; + if(previous != nullptr) { + insertAfter(previous, entry); + } + if(previous == nullptr) { + m_cut[0].m_begin = entry->m_idx; + } + previous = entry; + } + } + } + + ShadowCache::ShadowGroup* ShadowCache::createCut(ShadowGroup* group) { + ShadowGroup* child = allocGroup(); + child->m_parent = group->m_idx; + if (group->m_child == UINT16_MAX) { + group->m_child = child->m_idx; + child->m_parent = group->m_idx; + } else { + insertAfter(&m_alloc[group->m_child], child); + } + child->m_level = group->m_level + 1; + bool found = false; + for (uint8_t i = 0; i < 4; i++) { + if ((group->m_occupyMask & (1 << i)) == 0) { + group->m_occupyMask |= (1 << i); // we are going to set this entry is occupied + uint16_t x = (i % 2); + uint16_t y = (i / 2); + child->m_slot = i; // we assign the slot we occupy for this cut + uint2 quadSize = m_quadSize / (1 << child->m_level); + group->m_x = group->m_x + (x * quadSize.x); + group->m_y = group->m_y + (y * quadSize.y); + group->m_flags |= ShadowGroup::HasGroups; + found = true; + break; + } + } + ASSERT(found); + auto& nextCut = m_cut[child->m_level]; + if (nextCut.m_begin == UINT16_MAX) { + nextCut.m_begin = child->m_idx; + } else { + insertBefore(&m_alloc[nextCut.m_begin], group); + } + + return child; + } + + uint4 ShadowCache::find(uint16_t hash, uint8_t level, uint32_t age) { + auto findGroupInCut = [&](ShadowGroup* group) { + ShadowGroup* result = nullptr; + for (uint16_t i = group->m_idx; i != UINT16_MAX; i = m_alloc[i].m_next) { + for(size_t k = 0; k < 4; k++) { + // we found a matching hash + if(m_alloc[i].m_hashes[k] == hash) { + result = &m_alloc[i]; + goto exit; + } + } + if (result == nullptr || m_alloc[i].m_age < result->m_age) { + result = &m_alloc[i]; + } + } + exit: + return result; + }; + const uint8_t targetLevel = level == 0? 0: level - 1; + auto& targetCut = m_cut[targetLevel]; + + ShadowGroup* group = findGroupInCut(&m_alloc[targetCut.m_begin]); + if(level == 0) { + freeChildren(group); + group->m_flags |= ShadowGroup::IsLeaf; + group->m_hashes[0] = hash; + group->m_age = age; + return uint4(group->m_x, group->m_y, m_quadSize.x, m_quadSize.y); + } else { + + } + return uint4(0,0,0,0); + } + + ShadowCache::ShadowGroup* ShadowCache::allocGroup() { + uint32_t index = m_pool.requestId(); + ShadowGroup* entry = &m_alloc[index]; + std::memset(entry, 0, sizeof(ShadowGroup)); + entry->m_parent = UINT16_MAX; + entry->m_child = UINT16_MAX; + entry->m_next = UINT16_MAX; + entry->m_prev = UINT16_MAX; + entry->m_idx = index; + return entry; + } + + void ShadowCache::updateAge(ShadowCache::ShadowGroup* current, uint32_t age) { + for(uint16_t i = current->m_idx; i != UINT16_MAX; i = m_alloc[i].m_parent) { + if(age > current->m_age ) { + current->m_age = age; + } + } + } + + void ShadowCache::freeChildren(ShadowCache::ShadowGroup* grp) { + if(grp->m_child != UINT16_MAX) { + for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { + m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent + freeGroup(&m_alloc[i]); + } + } + std::memset(grp->m_hashes, 0, sizeof(grp->m_hashes)); + grp->m_occupyMask = 0; + grp->m_flags &= ~(ShadowGroup::HasLeafs | ShadowGroup::HasGroups); + } + void ShadowCache::freeGroup(ShadowCache::ShadowGroup* grp) { + for(auto& cut: m_cut) { + if(cut.m_begin == grp->m_idx) { + cut.m_begin = grp->m_next; // we assign the next if UINT16_MAX then that is accepted the layer is now empty + } + } + if(grp->m_child != UINT16_MAX) { + for(uint32_t i = grp->m_child; i != UINT16_MAX && m_alloc[i].m_parent == grp->m_idx; i = m_alloc[i].m_next) { + m_alloc[i].m_parent = UINT16_MAX; // we invalidate the parent + freeGroup(&m_alloc[i]); + } + } + if(grp->m_parent != UINT16_MAX) { + auto* parent = &m_alloc[grp->m_parent]; + parent->m_occupyMask &= ~(1 << grp->m_slot); // we clear the occupy slot + if(parent->m_child == grp->m_idx) { + // if the next child has a mismatched index we've exausted cuts + if(grp->m_next != UINT16_MAX && m_alloc[grp->m_next].m_parent == parent->m_idx) { + parent->m_child = grp->m_next; + } + + } + } + if(grp->m_prev != UINT16_MAX && grp->m_next != UINT16_MAX) { + m_alloc[grp->m_prev].m_next = m_alloc[grp->m_next].m_idx; + m_alloc[grp->m_next].m_prev = m_alloc[grp->m_prev].m_idx; + } else if(grp->m_prev != UINT16_MAX) { + m_alloc[grp->m_prev].m_next = UINT16_MAX; + } else if(grp->m_next != UINT16_MAX) { + m_alloc[grp->m_next].m_prev = UINT16_MAX; + } + m_pool.returnId(grp->m_idx); + } +}