Skip to content

Commit

Permalink
Multiple fixes and improvements to sphere map rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed May 13, 2024
1 parent bbb39bc commit e773ad4
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 75 deletions.
36 changes: 25 additions & 11 deletions Components/interface/EnvMapRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <unordered_map>
#include <vector>
#include <memory>
#include <array>

#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h"
#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h"
Expand Down Expand Up @@ -83,31 +84,37 @@ class EnvMapRenderer

struct PSOKey
{
const int ToneMappingMode;
const bool ConvertOutputToSRGB;
const bool ComputeMotionVectors;
const bool SamplingSphere;
enum ENV_MAP_TYPE : Uint8
{
ENV_MAP_TYPE_CUBE = 0,
ENV_MAP_TYPE_SPHERE,
ENV_MAP_TYPE_COUNT
};
const int ToneMappingMode;
const bool ConvertOutputToSRGB;
const bool ComputeMotionVectors;
const ENV_MAP_TYPE EnvMapType;

PSOKey(int _ToneMappingMode, bool _ConvertOutputToSRGB, bool _ComputeMotionVectors, bool _SamplingSphere) :
PSOKey(int _ToneMappingMode, bool _ConvertOutputToSRGB, bool _ComputeMotionVectors, ENV_MAP_TYPE _EnvMapType) :
ToneMappingMode{_ToneMappingMode},
ConvertOutputToSRGB{_ConvertOutputToSRGB},
ComputeMotionVectors{_ComputeMotionVectors},
SamplingSphere{_SamplingSphere}
EnvMapType{_EnvMapType}
{}

constexpr bool operator==(const PSOKey& rhs) const
{
return (ToneMappingMode == rhs.ToneMappingMode &&
ConvertOutputToSRGB == rhs.ConvertOutputToSRGB &&
ComputeMotionVectors == rhs.ComputeMotionVectors &&
SamplingSphere == rhs.SamplingSphere);
EnvMapType == rhs.EnvMapType);
}

struct Hasher
{
size_t operator()(const PSOKey& Key) const
{
return ComputeHash(Key.ToneMappingMode, Key.ConvertOutputToSRGB, Key.ComputeMotionVectors, Key.SamplingSphere);
return ComputeHash(Key.ToneMappingMode, Key.ConvertOutputToSRGB, Key.ComputeMotionVectors, Key.EnvMapType);
}
};
};
Expand All @@ -125,10 +132,17 @@ class EnvMapRenderer

std::unordered_map<PSOKey, RefCntAutoPtr<IPipelineState>, PSOKey::Hasher> m_PSOs;

IPipelineState* m_pCurrentPSO = nullptr;
struct Resources
{
RefCntAutoPtr<IShaderResourceBinding> SRB;
IShaderResourceVariable* pEnvMapVar = nullptr;

explicit operator bool() const { return SRB; }
};
std::array<Resources, PSOKey::ENV_MAP_TYPE_COUNT> m_Resources;

RefCntAutoPtr<IShaderResourceBinding> m_SRB;
IShaderResourceVariable* m_pEnvMapVar = nullptr;
IPipelineState* m_pCurrentPSO = nullptr;
IShaderResourceBinding* m_pCurrentSRB = nullptr;

struct EnvMapShaderAttribs;
std::unique_ptr<EnvMapShaderAttribs> m_ShaderAttribs;
Expand Down
24 changes: 16 additions & 8 deletions Components/src/EnvMapRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ IPipelineState* EnvMapRenderer::GetPSO(const PSOKey& Key)
.Add("CONVERT_OUTPUT_TO_SRGB", Key.ConvertOutputToSRGB)
.Add("TONE_MAPPING_MODE", Key.ToneMappingMode)
.Add("COMPUTE_MOTION_VECTORS", Key.ComputeMotionVectors)
.Add("SAMPLING_SPHERE", Key.SamplingSphere);
.Add("ENV_MAP_TYPE_CUBE", static_cast<int>(PSOKey::ENV_MAP_TYPE_CUBE))
.Add("ENV_MAP_TYPE_SPHERE", static_cast<int>(PSOKey::ENV_MAP_TYPE_SPHERE))
.Add("ENV_MAP_TYPE", static_cast<int>(Key.EnvMapType));
ShaderCI.Macros = Macros;

RefCntAutoPtr<IShader> pVS;
Expand Down Expand Up @@ -180,11 +182,12 @@ IPipelineState* EnvMapRenderer::GetPSO(const PSOKey& Key)
PSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "cbCameraAttribs")->Set(m_pCameraAttribsCB);
PSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "cbEnvMapRenderAttribs")->Set(m_RenderAttribsCB);

if (!m_SRB)
auto& Res = m_Resources[Key.EnvMapType];
if (!Res)
{
PSO->CreateShaderResourceBinding(&m_SRB, true);
m_pEnvMapVar = m_SRB->GetVariableByName(SHADER_TYPE_PIXEL, "EnvMap");
VERIFY_EXPR(m_pEnvMapVar != nullptr);
PSO->CreateShaderResourceBinding(&Res.SRB, true);
Res.pEnvMapVar = Res.SRB->GetVariableByName(SHADER_TYPE_PIXEL, "EnvMap");
VERIFY_EXPR(Res.pEnvMapVar != nullptr);
}

m_PSOs.emplace(Key, PSO);
Expand All @@ -201,15 +204,20 @@ void EnvMapRenderer::Prepare(IDeviceContext* pContext,
return;
}

const PSOKey::ENV_MAP_TYPE EnvMapType = Attribs.pEnvMap->GetTexture()->GetDesc().IsCube() ?
PSOKey::ENV_MAP_TYPE_CUBE :
PSOKey::ENV_MAP_TYPE_SPHERE;

m_pCurrentPSO = GetPSO({ToneMapping.iToneMappingMode, Attribs.ConvertOutputToSRGB, Attribs.ComputeMotionVectors, !Attribs.pEnvMap->GetTexture()->GetDesc().IsCube()});
m_pCurrentPSO = GetPSO({ToneMapping.iToneMappingMode, Attribs.ConvertOutputToSRGB, Attribs.ComputeMotionVectors, EnvMapType});
if (m_pCurrentPSO == nullptr)
{
UNEXPECTED("Failed to get PSO");
return;
}

m_pEnvMapVar->Set(Attribs.pEnvMap);
m_Resources[EnvMapType].pEnvMapVar->Set(Attribs.pEnvMap);
m_pCurrentSRB = m_Resources[EnvMapType].SRB;
VERIFY_EXPR(m_pCurrentSRB != nullptr);

if (m_ShaderAttribs)
{
Expand Down Expand Up @@ -253,7 +261,7 @@ void EnvMapRenderer::Render(IDeviceContext* pContext)
}

pContext->SetPipelineState(m_pCurrentPSO);
pContext->CommitShaderResources(m_SRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
pContext->CommitShaderResources(m_pCurrentSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
DrawAttribs drawAttribs{3, DRAW_FLAG_VERIFY_ALL};
pContext->Draw(drawAttribs);
}
Expand Down
39 changes: 31 additions & 8 deletions PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,28 +681,51 @@ class PBR_Renderer
{
IBL_FEATURE_FLAG_NONE = 0,
IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES = 1u << 0u,
IBL_FEATURE_FLAG_SAMPLING_SPHERE = 1u << 1u
};
DECLARE_FRIEND_FLAG_ENUM_OPERATORS(IBL_FEATURE_FLAGS)

struct IBL_PSOKey
{
enum PSO_TYPE : Uint8
{
PSO_TYPE_IRRADIANCE_CUBE = 0,
PSO_TYPE_PREFILTERED_ENV_MAP,
};
enum ENV_MAP_TYPE : Uint8
{
ENV_MAP_TYPE_CUBE = 0,
ENV_MAP_TYPE_SPHERE,
ENV_MAP_TYPE_NUM_TYPES
};

const PSO_TYPE PSOType;
const ENV_MAP_TYPE EnvMapType;
const IBL_FEATURE_FLAGS FeatureFlags;
const TEXTURE_FORMAT RTVFormat;

IBL_PSOKey(IBL_FEATURE_FLAGS _FeatureFlags, TEXTURE_FORMAT Format) :
FeatureFlags{_FeatureFlags}, RTVFormat{Format}
IBL_PSOKey(PSO_TYPE _PSOType,
ENV_MAP_TYPE _EnvMapType,
IBL_FEATURE_FLAGS _FeatureFlags,
TEXTURE_FORMAT _Format) :
PSOType{_PSOType},
EnvMapType{_EnvMapType},
FeatureFlags{_FeatureFlags},
RTVFormat{_Format}
{}

constexpr bool operator==(const IBL_PSOKey& rhs) const
{
return FeatureFlags == rhs.FeatureFlags && RTVFormat == rhs.RTVFormat;
return (PSOType == rhs.PSOType &&
EnvMapType == rhs.EnvMapType &&
FeatureFlags == rhs.FeatureFlags &&
RTVFormat == rhs.RTVFormat);
}

struct Hasher
{
size_t operator()(const IBL_PSOKey& Key) const
{
return ComputeHash(Key.FeatureFlags, Key.RTVFormat);
return ComputeHash(Key.PSOType, Key.EnvMapType, Key.FeatureFlags, Key.RTVFormat);
}
};
};
Expand Down Expand Up @@ -733,8 +756,8 @@ class PBR_Renderer
RefCntAutoPtr<ITextureView> m_pIrradianceCubeSRV;
RefCntAutoPtr<ITextureView> m_pPrefilteredEnvMapSRV;

RefCntAutoPtr<IShaderResourceBinding> m_pPrecomputeIrradianceCubeSRB;
RefCntAutoPtr<IShaderResourceBinding> m_pPrefilterEnvMapSRB;
std::array<RefCntAutoPtr<IShaderResourceBinding>, IBL_PSOKey::ENV_MAP_TYPE_NUM_TYPES> m_pPrecomputeIrradianceCubeSRB;
std::array<RefCntAutoPtr<IShaderResourceBinding>, IBL_PSOKey::ENV_MAP_TYPE_NUM_TYPES> m_pPrefilterEnvMapSRB;

IBL_PipelineStateObjectCache m_IBL_PSOCache;

Expand All @@ -750,7 +773,7 @@ class PBR_Renderer
};

DEFINE_FLAG_ENUM_OPERATORS(PBR_Renderer::PSO_FLAGS)

DEFINE_FLAG_ENUM_OPERATORS(PBR_Renderer::IBL_FEATURE_FLAGS)

inline constexpr PBR_Renderer::PSO_FLAGS PBR_Renderer::GetTextureAttribPSOFlag(PBR_Renderer::TEXTURE_ATTRIB_ID AttribId)
{
Expand Down
44 changes: 23 additions & 21 deletions PBR/src/PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,18 +493,22 @@ void PBR_Renderer::PrecomputeCubemaps(IDeviceContext* pCtx,
IBL_FEATURE_FLAGS FeatureFlags = IBL_FEATURE_FLAG_NONE;

if (OptimizeSamples)
FeatureFlags = static_cast<IBL_FEATURE_FLAGS>(FeatureFlags | IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES);
FeatureFlags |= IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES;

if (!pEnvironmentMap->GetTexture()->GetDesc().IsCube())
FeatureFlags = static_cast<IBL_FEATURE_FLAGS>(FeatureFlags | IBL_FEATURE_FLAG_SAMPLING_SPHERE);
const IBL_PSOKey::ENV_MAP_TYPE EnvMapType = pEnvironmentMap->GetTexture()->GetDesc().IsCube() ?
IBL_PSOKey::ENV_MAP_TYPE_CUBE :
IBL_PSOKey::ENV_MAP_TYPE_SPHERE;

auto& pPrecomputeIrradianceCubePSO = m_IBL_PSOCache[IBL_PSOKey{FeatureFlags, m_pIrradianceCubeSRV->GetDesc().Format}];
ShaderMacroHelper Macros;
Macros
.Add("OPTIMIZE_SAMPLES", (FeatureFlags & IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES) != 0)
.Add("ENV_MAP_TYPE_CUBE", static_cast<int>(IBL_PSOKey::ENV_MAP_TYPE_CUBE))
.Add("ENV_MAP_TYPE_SPHERE", static_cast<int>(IBL_PSOKey::ENV_MAP_TYPE_SPHERE))
.Add("ENV_MAP_TYPE", static_cast<int>(EnvMapType));

auto& pPrecomputeIrradianceCubePSO = m_IBL_PSOCache[IBL_PSOKey{IBL_PSOKey::PSO_TYPE_IRRADIANCE_CUBE, EnvMapType, FeatureFlags, m_pIrradianceCubeSRV->GetDesc().Format}];
if (!pPrecomputeIrradianceCubePSO)
{
ShaderMacroHelper Macros;
Macros.AddShaderMacro("OPTIMIZE_SAMPLES", (FeatureFlags & IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES) != 0);
Macros.AddShaderMacro("SAMPLING_SPHERE", (FeatureFlags & IBL_FEATURE_FLAG_SAMPLING_SPHERE) != 0);

ShaderCreateInfo ShaderCI;
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
ShaderCI.pShaderSourceStreamFactory = &DiligentFXShaderSourceStreamFactory::GetInstance();
Expand Down Expand Up @@ -557,16 +561,13 @@ void PBR_Renderer::PrecomputeCubemaps(IDeviceContext* pCtx,
pPrecomputeIrradianceCubePSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "FilterAttribs")->Set(m_PrecomputeEnvMapAttribsCB);
}

if (!m_pPrecomputeIrradianceCubeSRB)
pPrecomputeIrradianceCubePSO->CreateShaderResourceBinding(&m_pPrecomputeIrradianceCubeSRB, true);
auto& pPrecomputeIrradianceCubeSRB = m_pPrecomputeIrradianceCubeSRB[EnvMapType];
if (!pPrecomputeIrradianceCubeSRB)
pPrecomputeIrradianceCubePSO->CreateShaderResourceBinding(&pPrecomputeIrradianceCubeSRB, true);

auto& pPrefilterEnvMapPSO = m_IBL_PSOCache[IBL_PSOKey{FeatureFlags, m_pPrefilteredEnvMapSRV->GetDesc().Format}];
auto& pPrefilterEnvMapPSO = m_IBL_PSOCache[IBL_PSOKey{IBL_PSOKey::PSO_TYPE_PREFILTERED_ENV_MAP, EnvMapType, FeatureFlags, m_pPrefilteredEnvMapSRV->GetDesc().Format}];
if (!pPrefilterEnvMapPSO)
{
ShaderMacroHelper Macros;
Macros.AddShaderMacro("OPTIMIZE_SAMPLES", (FeatureFlags & IBL_FEATURE_FLAG_OPTIMIZE_SAMPLES) != 0);
Macros.AddShaderMacro("SAMPLING_SPHERE", (FeatureFlags & IBL_FEATURE_FLAG_SAMPLING_SPHERE) != 0);

ShaderCreateInfo ShaderCI;
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
ShaderCI.pShaderSourceStreamFactory = &DiligentFXShaderSourceStreamFactory::GetInstance();
Expand Down Expand Up @@ -619,8 +620,9 @@ void PBR_Renderer::PrecomputeCubemaps(IDeviceContext* pCtx,
pPrefilterEnvMapPSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "FilterAttribs")->Set(m_PrecomputeEnvMapAttribsCB);
}

if (!m_pPrefilterEnvMapSRB)
pPrefilterEnvMapPSO->CreateShaderResourceBinding(&m_pPrefilterEnvMapSRB, true);
auto& pPrefilterEnvMapSRB = m_pPrefilterEnvMapSRB[EnvMapType];
if (!pPrefilterEnvMapSRB)
pPrefilterEnvMapPSO->CreateShaderResourceBinding(&pPrefilterEnvMapSRB, true);

// clang-format off
const std::array<float4x4, 6> Matrices =
Expand All @@ -635,8 +637,8 @@ void PBR_Renderer::PrecomputeCubemaps(IDeviceContext* pCtx,
// clang-format on

pCtx->SetPipelineState(pPrecomputeIrradianceCubePSO);
m_pPrecomputeIrradianceCubeSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_EnvironmentMap")->Set(pEnvironmentMap);
pCtx->CommitShaderResources(m_pPrecomputeIrradianceCubeSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
pPrecomputeIrradianceCubeSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_EnvironmentMap")->Set(pEnvironmentMap);
pCtx->CommitShaderResources(pPrecomputeIrradianceCubeSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
auto* pIrradianceCube = m_pIrradianceCubeSRV->GetTexture();

for (Uint32 face = 0; face < 6; ++face)
Expand All @@ -661,8 +663,8 @@ void PBR_Renderer::PrecomputeCubemaps(IDeviceContext* pCtx,
}

pCtx->SetPipelineState(pPrefilterEnvMapPSO);
m_pPrefilterEnvMapSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_EnvironmentMap")->Set(pEnvironmentMap);
pCtx->CommitShaderResources(m_pPrefilterEnvMapSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
pPrefilterEnvMapSRB->GetVariableByName(SHADER_TYPE_PIXEL, "g_EnvironmentMap")->Set(pEnvironmentMap);
pCtx->CommitShaderResources(pPrefilterEnvMapSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
auto* pPrefilteredEnvMap = m_pPrefilteredEnvMapSRV->GetTexture();
const auto& PrefilteredEnvMapDesc = pPrefilteredEnvMap->GetDesc();
for (Uint32 mip = 0; mip < PrefilteredEnvMapDesc.MipLevels; ++mip)
Expand Down
13 changes: 6 additions & 7 deletions Shaders/Common/private/EnvMap.psh
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include "BasicStructures.fxh"
#include "ToneMapping.fxh"
#include "ShaderUtilities.fxh"
#include "PBR_PrecomputeCommon.fxh"

cbuffer cbCameraAttribs
{
Expand All @@ -19,19 +18,19 @@ cbuffer cbEnvMapRenderAttribs
float Unusued2;
}

#if SAMPLING_SPHERE
Texture2D EnvMap;
#else
#if ENV_MAP_TYPE == ENV_MAP_TYPE_CUBE
TextureCube EnvMap;
#elif ENV_MAP_TYPE == ENV_MAP_TYPE_SPHERE
Texture2D EnvMap;
#endif
SamplerState EnvMap_sampler;

float3 SampleEnvrionmentMap(float3 R, float MipLevel)
{
#if SAMPLING_SPHERE
return EnvMap.SampleLevel(EnvMap_sampler, TransformDirectionToSpherePoint(R), MipLevel).rgb;
#else
#if ENV_MAP_TYPE == ENV_MAP_TYPE_CUBE
return EnvMap.SampleLevel(EnvMap_sampler, R, MipLevel).rgb;
#elif ENV_MAP_TYPE == ENV_MAP_TYPE_SPHERE
return EnvMap.SampleLevel(EnvMap_sampler, TransformDirectionToSphereMapUV(R), MipLevel).rgb;
#endif
}

Expand Down
6 changes: 6 additions & 0 deletions Shaders/Common/public/ShaderUtilities.fxh
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,10 @@ float2 GetMotionVector(float2 ClipPos, float2 PrevClipPos)
return ClipPos - PrevClipPos;
}

float2 TransformDirectionToSphereMapUV(float3 Direction)
{
float OneOverPi = 0.3183098862;
return OneOverPi * float2(0.5 * atan2(Direction.z, Direction.x), asin(Direction.y)) + float2(0.5, 0.5);
}

#endif //_SHADER_UTILITIES_FXH_
21 changes: 14 additions & 7 deletions Shaders/PBR/private/ComputeIrradianceMap.psh
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
// Generates an irradiance cube from an environment map using convolution

#include "PBR_PrecomputeCommon.fxh"
#include "ShaderUtilities.fxh"

#ifndef OPTIMIZE_SAMPLES
# define OPTIMIZE_SAMPLES 1
#endif

#if SAMPLING_SPHERE
Texture2D g_EnvironmentMap;
#else
#if ENV_MAP_TYPE == ENV_MAP_TYPE_CUBE
TextureCube g_EnvironmentMap;
#elif ENV_MAP_TYPE == ENV_MAP_TYPE_SPHERE
Texture2D g_EnvironmentMap;
#endif

SamplerState g_EnvironmentMap_sampler;

cbuffer FilterAttribs
Expand All @@ -25,10 +27,10 @@ cbuffer FilterAttribs

float3 SampleEnvrionmentMap(float3 R, float MipLevel)
{
#if SAMPLING_SPHERE
return g_EnvironmentMap.SampleLevel(g_EnvironmentMap_sampler, TransformDirectionToSpherePoint(R), MipLevel).rgb;
#else
#if ENV_MAP_TYPE == ENV_MAP_TYPE_CUBE
return g_EnvironmentMap.SampleLevel(g_EnvironmentMap_sampler, R, MipLevel).rgb;
#elif ENV_MAP_TYPE == ENV_MAP_TYPE_SPHERE
return g_EnvironmentMap.SampleLevel(g_EnvironmentMap_sampler, TransformDirectionToSphereMapUV(R), MipLevel).rgb;
#endif
}

Expand All @@ -55,8 +57,13 @@ float3 IrradianceMap(float3 N)
// Solid angle of current smple
float OmegaS = 1.0 / (float(g_NumSamples) * pdf);

float NumPixels = g_EnvMapWidth * g_EnvMapHeight;
#if ENV_MAP_TYPE == ENV_MAP_TYPE_CUBE
NumPixels *= 6.0;
#endif

// Solid angle of 1 pixel across all cube faces
float OmegaP = 4.0 * PI / (6.0 * g_EnvMapWidth * g_EnvMapHeight);
float OmegaP = 4.0 * PI / NumPixels;

// Applying mip bias produces better results, especially for environments maps with
// very bright spots.
Expand Down
Loading

0 comments on commit e773ad4

Please sign in to comment.