Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 49 additions & 7 deletions PBR/interface/GLTF_PBR_Renderer.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2019-2026 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -97,6 +97,35 @@ class GLTF_PBR_Renderer : public PBR_Renderer
/// Flag indicating which alpha modes to render
ALPHA_MODE_FLAGS AlphaModes = ALPHA_MODE_FLAG_ALL;

enum SURFACE_FLAGS : Uint32
{
/// Render nothing
SURFACE_FLAG_NONE = 0,

/// Render non-transmission opaque materials
SURFACE_FLAG_OPAQUE = 1u << 0u,

/// Render non-transmission alpha-masked materials
SURFACE_FLAG_MASK = 1u << 1u,

/// Render transmission composite materials
SURFACE_FLAG_TRANSMISSION = 1u << 2u,

/// Render non-transmission alpha-blended materials
SURFACE_FLAG_BLEND = 1u << 3u,

/// Render all surface buckets
SURFACE_FLAG_ALL = SURFACE_FLAG_OPAQUE | SURFACE_FLAG_MASK | SURFACE_FLAG_TRANSMISSION | SURFACE_FLAG_BLEND
};
/// Flag indicating which derived surface buckets to render.
SURFACE_FLAGS SurfaceFlags = SURFACE_FLAG_ALL;

/// Copied linear HDR scene color texture used by transmission composite.
ITextureView* pTransmissionSceneColorSRV = nullptr;

/// Optional camera position used to sort transmissive surfaces back-to-front.
const float3* pCameraPosition = nullptr;

DebugViewType DebugView = DebugViewType::None;

PSO_FLAGS Flags = PSO_FLAG_DEFAULT;
Expand Down Expand Up @@ -269,23 +298,36 @@ class GLTF_PBR_Renderer : public PBR_Renderer
private:
RenderInfo m_RenderParams;

enum RENDER_LIST_ID : size_t
{
RENDER_LIST_OPAQUE = 0,
RENDER_LIST_MASK,
RENDER_LIST_TRANSMISSION,
RENDER_LIST_BLEND,
RENDER_LIST_COUNT
};

struct PrimitiveRenderInfo
{
const GLTF::Primitive& Primitive;
const GLTF::Node& Node;
const GLTF::Primitive* Primitive = nullptr;
const GLTF::Node* Node = nullptr;
float SortDistanceSq = 0;

PrimitiveRenderInfo(const GLTF::Primitive& _Primitive,
const GLTF::Node& _Node) noexcept :
Primitive{_Primitive},
Node{_Node}
const GLTF::Node& _Node,
float _SortDistanceSq = 0) noexcept :
Primitive{&_Primitive},
Node{&_Node},
SortDistanceSq{_SortDistanceSq}
{}
};
std::array<std::vector<PrimitiveRenderInfo>, GLTF::Material::ALPHA_MODE_NUM_MODES> m_RenderLists;
std::array<std::vector<PrimitiveRenderInfo>, RENDER_LIST_COUNT> m_RenderLists;

PsoCacheAccessor m_PbrPSOCache;
PsoCacheAccessor m_WireframePSOCache;
};

DEFINE_FLAG_ENUM_OPERATORS(GLTF_PBR_Renderer::RenderInfo::ALPHA_MODE_FLAGS)
DEFINE_FLAG_ENUM_OPERATORS(GLTF_PBR_Renderer::RenderInfo::SURFACE_FLAGS)

} // namespace Diligent
7 changes: 5 additions & 2 deletions PBR/interface/PBR_Renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -592,9 +592,10 @@ class PBR_Renderer
PSO_FLAG_ENABLE_TONE_MAPPING = PSO_FLAG_BIT(35),
PSO_FLAG_UNSHADED = PSO_FLAG_BIT(36),
PSO_FLAG_COMPUTE_MOTION_VECTORS = PSO_FLAG_BIT(37),
PSO_FLAG_ENABLE_SHADOWS = PSO_FLAG_BIT(38),
PSO_FLAG_ENABLE_SHADOWS = PSO_FLAG_BIT(38),
PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE = PSO_FLAG_BIT(39),

PSO_FLAG_LAST = PSO_FLAG_ENABLE_SHADOWS,
PSO_FLAG_LAST = PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE,

PSO_FLAG_FIRST_USER_DEFINED = PSO_FLAG_LAST << 1ull,

Expand Down Expand Up @@ -782,6 +783,8 @@ class PBR_Renderer
ITextureView* pIrradianceCubeSRV,
ITextureView* pPrefilteredEnvMapSRV) const;

void SetTransmissionSceneColor(IShaderResourceBinding* pSRB, ITextureView* pSceneColorSRV) const;

void SetOITResources(IShaderResourceBinding* pSRB, const OITResources& OITResources) const;

/// Initializes internal renderer parameters.
Expand Down
89 changes: 79 additions & 10 deletions PBR/src/GLTF_PBR_Renderer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 Diligent Graphics LLC
* Copyright 2019-2026 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -565,6 +565,18 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
for (std::vector<PrimitiveRenderInfo>& List : m_RenderLists)
List.clear();

auto GetTransmissionSortDistanceSq = [&](const GLTF::Primitive& Primitive, const GLTF::Node& Node) //
{
if (RenderParams.pCameraPosition == nullptr)
return 0.f;

const float4x4 NodeTransform = Transforms.NodeGlobalMatrices[Node.Index] * RenderParams.ModelTransform;
const BoundBox WorldBB = Primitive.BB.Transform(NodeTransform);
const float3 Center = (WorldBB.Min + WorldBB.Max) * 0.5f;
const float3 Delta = Center - *RenderParams.pCameraPosition;
return dot(Delta, Delta);
};

for (const GLTF::Node* pNode : Scene.LinearNodes)
{
VERIFY_EXPR(pNode != nullptr);
Expand All @@ -581,18 +593,54 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
if ((RenderParams.AlphaModes & (1u << AlphaMode)) == 0)
continue;

m_RenderLists[AlphaMode].emplace_back(primitive, *pNode);
RENDER_LIST_ID RenderListId = RENDER_LIST_OPAQUE;
RenderInfo::SURFACE_FLAGS SurfaceFlag = RenderInfo::SURFACE_FLAG_OPAQUE;

const bool IsTransmissive = m_Settings.EnableTransmission &&
Material.Transmission != nullptr &&
Material.Transmission->Factor > 0.f;
if (IsTransmissive)
{
RenderListId = RENDER_LIST_TRANSMISSION;
SurfaceFlag = RenderInfo::SURFACE_FLAG_TRANSMISSION;
}
else if (Material.Attribs.AlphaMode == GLTF::Material::ALPHA_MODE_MASK)
{
RenderListId = RENDER_LIST_MASK;
SurfaceFlag = RenderInfo::SURFACE_FLAG_MASK;
}
else if (Material.Attribs.AlphaMode == GLTF::Material::ALPHA_MODE_BLEND)
{
RenderListId = RENDER_LIST_BLEND;
SurfaceFlag = RenderInfo::SURFACE_FLAG_BLEND;
}

if ((RenderParams.SurfaceFlags & SurfaceFlag) == 0)
continue;

m_RenderLists[RenderListId].emplace_back(primitive, *pNode, GetTransmissionSortDistanceSq(primitive, *pNode));
}
}

if (RenderParams.pCameraPosition != nullptr)
{
std::vector<PrimitiveRenderInfo>& TransmissionList = m_RenderLists[RENDER_LIST_TRANSMISSION];
std::sort(TransmissionList.begin(), TransmissionList.end(),
[](const PrimitiveRenderInfo& LHS, const PrimitiveRenderInfo& RHS) //
{
return LHS.SortDistanceSq > RHS.SortDistanceSq;
});
}

const Uint32 FirstIndexLocation = GLTFModel.GetFirstIndexLocation();
const Uint32 BaseVertex = GLTFModel.GetBaseVertex();

const std::array<GLTF::Material::ALPHA_MODE, 3> AlphaModes //
const std::array<RENDER_LIST_ID, RENDER_LIST_COUNT> RenderListIds //
{
GLTF::Material::ALPHA_MODE_OPAQUE, // Opaque primitives - first
GLTF::Material::ALPHA_MODE_MASK, // Alpha-masked primitives - second
GLTF::Material::ALPHA_MODE_BLEND, // Transparent primitives - last (TODO: depth sorting)
RENDER_LIST_OPAQUE, // Non-transmission opaque primitives - first
RENDER_LIST_MASK, // Non-transmission alpha-masked primitives - second
RENDER_LIST_TRANSMISSION, // Transmission composite primitives - third
RENDER_LIST_BLEND, // Non-transmission alpha-blended primitives - last
};

IPipelineState* pCurrPSO = nullptr;
Expand All @@ -603,14 +651,21 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
if (PrevTransforms == nullptr)
PrevTransforms = &Transforms;

for (GLTF::Material::ALPHA_MODE AlphaMode : AlphaModes)
for (RENDER_LIST_ID RenderListId : RenderListIds)
{
const std::vector<PrimitiveRenderInfo>& RenderList = m_RenderLists[AlphaMode];
pCurrPSO = nullptr;
pCurrSRB = nullptr;
pCurrMaterial = nullptr;

const bool IsTransmissionList = RenderListId == RENDER_LIST_TRANSMISSION;
const std::vector<PrimitiveRenderInfo>& RenderList = m_RenderLists[RenderListId];
for (const PrimitiveRenderInfo& PrimRI : RenderList)
{
const GLTF::Node& Node = PrimRI.Node;
const GLTF::Primitive& primitive = PrimRI.Primitive;
VERIFY_EXPR(PrimRI.Node != nullptr && PrimRI.Primitive != nullptr);
const GLTF::Node& Node = *PrimRI.Node;
const GLTF::Primitive& primitive = *PrimRI.Primitive;
const GLTF::Material& material = GLTFModel.Materials[primitive.MaterialId];
const auto AlphaMode = static_cast<GLTF::Material::ALPHA_MODE>(material.Attribs.AlphaMode);
const float4x4& NodeGlobalMatrix = Transforms.NodeGlobalMatrices[Node.Index];
const float4x4& PrevNodeGlobalMatrix = PrevTransforms->NodeGlobalMatrices[Node.Index];

Expand All @@ -629,7 +684,13 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
PSOFlags |= PSO_FLAG_USE_IBL;
}

if (IsTransmissionList && RenderParams.pTransmissionSceneColorSRV != nullptr)
{
PSOFlags |= PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE;
}

PSOFlags &= RenderParams.Flags;
const bool IsTransmissionComposite = (PSOFlags & PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE) != PSO_FLAG_NONE;

if (RenderParams.Wireframe)
PSOFlags |= PSO_FLAG_UNSHADED;
Expand Down Expand Up @@ -669,6 +730,10 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
if (pCurrSRB != pSRB)
{
pCurrSRB = pSRB;
if (IsTransmissionComposite)
{
SetTransmissionSceneColor(pSRB, RenderParams.pTransmissionSceneColorSRV);
}
pCtx->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
}
}
Expand All @@ -678,6 +743,10 @@ void GLTF_PBR_Renderer::Render(IDeviceContext* pCtx,
if (pCurrSRB != pCacheBindings->pSRB)
{
pCurrSRB = pCacheBindings->pSRB;
if (IsTransmissionComposite)
{
SetTransmissionSceneColor(pCurrSRB, RenderParams.pTransmissionSceneColorSRV);
}
pCtx->CommitShaderResources(pCurrSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
}
}
Expand Down
47 changes: 39 additions & 8 deletions PBR/src/PBR_Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ PBR_Renderer::PSOKey::PSOKey(RenderPassType _Type,
LoadingAnimation{_LoadingAnimation},
UserValue{_UserValue}
{
static_assert(PSO_FLAG_LAST == Uint64{1} << Uint64{38}, "Please handle the new flag below, if necessary");
static_assert(PSO_FLAG_LAST == Uint64{1} << Uint64{39}, "Please handle the new flag below, if necessary");
static_assert(static_cast<size_t>(RenderPassType::Count) == 3, "Please handle the new render pass type below, if necessary");
if (Type == RenderPassType::Shadow)
{
Expand Down Expand Up @@ -210,8 +210,9 @@ std::string PBR_Renderer::GetPSOFlagsString(PSO_FLAGS Flags)
case PSO_FLAG_ENABLE_SHEEN: FlagsStr += "SHEEN"; break;
case PSO_FLAG_ENABLE_ANISOTROPY: FlagsStr += "ANISOTROPY"; break;
case PSO_FLAG_ENABLE_IRIDESCENCE: FlagsStr += "IRIDESCENCE"; break;
case PSO_FLAG_ENABLE_TRANSMISSION: FlagsStr += "TRANSMISSION"; break;
case PSO_FLAG_ENABLE_VOLUME: FlagsStr += "VOLUME"; break;
case PSO_FLAG_ENABLE_TRANSMISSION: FlagsStr += "TRANSMISSION"; break;
case PSO_FLAG_ENABLE_VOLUME: FlagsStr += "VOLUME"; break;
case PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE: FlagsStr += "TRANSMISSION_COMPOSITE"; break;

case PSO_FLAG_USE_IBL: FlagsStr += "IBL"; break;
case PSO_FLAG_USE_LIGHTS: FlagsStr += "LIGHTS"; break;
Expand All @@ -229,7 +230,7 @@ std::string PBR_Renderer::GetPSOFlagsString(PSO_FLAGS Flags)
FlagsStr += std::to_string(PlatformMisc::GetLSB(Flag));
}
}
static_assert(PSO_FLAG_LAST == 1ull << 38ull, "Please update the switch above to handle the new flag");
static_assert(PSO_FLAG_LAST == 1ull << 39ull, "Please update the switch above to handle the new flag");

return FlagsStr;
}
Expand Down Expand Up @@ -1062,6 +1063,23 @@ void PBR_Renderer::SetOITResources(IShaderResourceBinding* pSRB, const OITResour
}
}

void PBR_Renderer::SetTransmissionSceneColor(IShaderResourceBinding* pSRB, ITextureView* pSceneColorSRV) const
{
if (!m_Settings.EnableTransmission || pSceneColorSRV == nullptr)
return;

if (pSRB == nullptr)
{
UNEXPECTED("SRB must not be null");
return;
}

if (ShaderResourceVariableX Var{pSRB, SHADER_TYPE_PIXEL, "g_TransmissionSceneColor"})
{
Var.Set(pSceneColorSRV, SET_SHADER_RESOURCE_FLAG_ALLOW_OVERWRITE);
}
}

void PBR_Renderer::SetMaterialTexture(IShaderResourceBinding* pSRB, ITextureView* pTexSRV, TEXTURE_ATTRIB_ID TextureId) const
{
if (m_Settings.ShaderTexturesArrayMode == SHADER_TEXTURE_ARRAY_MODE_NONE)
Expand Down Expand Up @@ -1258,6 +1276,12 @@ void PBR_Renderer::CreateSignature()
}
};

if (m_Settings.EnableTransmission)
{
constexpr WebGPUResourceAttribs WGPUSceneColor{WEB_GPU_BINDING_TYPE_DEFAULT, RESOURCE_DIM_TEX_2D};
AddTextureAndSampler("g_TransmissionSceneColor", Sam_LinearClamp, "g_LinearClampSampler", SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, WGPUSceneColor);
}

if (m_Settings.EnableIBL)
{
constexpr WebGPUResourceAttribs WGPUCubeMap{WEB_GPU_BINDING_TYPE_DEFAULT, RESOURCE_DIM_TEX_CUBE};
Expand Down Expand Up @@ -1474,7 +1498,7 @@ ShaderMacroHelper PBR_Renderer::DefineMacros(const PSOKey& Key) const
Macros.Add("LOADING_ANIMATION_TRANSITIONING", static_cast<int>(LoadingAnimationMode::Transitioning));
// clang-format on

static_assert(PSO_FLAG_LAST == PSO_FLAG_BIT(38), "Did you add new PSO Flag? You may need to handle it here.");
static_assert(PSO_FLAG_LAST == PSO_FLAG_BIT(39), "Did you add new PSO Flag? You may need to handle it here.");
#define ADD_PSO_FLAG_MACRO(Flag) Macros.Add(#Flag, (PSOFlags & PSO_FLAG_##Flag) != PSO_FLAG_NONE)
ADD_PSO_FLAG_MACRO(USE_COLOR_MAP);
ADD_PSO_FLAG_MACRO(USE_NORMAL_MAP);
Expand Down Expand Up @@ -1506,6 +1530,7 @@ ShaderMacroHelper PBR_Renderer::DefineMacros(const PSOKey& Key) const
ADD_PSO_FLAG_MACRO(ENABLE_IRIDESCENCE);
ADD_PSO_FLAG_MACRO(ENABLE_TRANSMISSION);
ADD_PSO_FLAG_MACRO(ENABLE_VOLUME);
ADD_PSO_FLAG_MACRO(ENABLE_TRANSMISSION_COMPOSITE);

ADD_PSO_FLAG_MACRO(USE_IBL);

Expand Down Expand Up @@ -1930,8 +1955,9 @@ void PBR_Renderer::CreatePSO(PsoHashMapType& PsoHashMap,
Macros.Add("USE_GL_POINT_SIZE", "1");
}

const bool IsTransmissionComposite = (PSOFlags & PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE) != PSO_FLAG_NONE;
const Uint32 OITLayerCount = (Key.GetType() == RenderPassType::OITLayers) ||
(Key.GetType() == RenderPassType::Main && Key.GetAlphaMode() == ALPHA_MODE_BLEND) ?
(Key.GetType() == RenderPassType::Main && Key.GetAlphaMode() == ALPHA_MODE_BLEND && !IsTransmissionComposite) ?
m_Settings.OITLayerCount :
0;
Macros.Add("NUM_OIT_LAYERS", static_cast<int>(OITLayerCount));
Expand Down Expand Up @@ -2063,6 +2089,11 @@ void PBR_Renderer::CreatePSO(PsoHashMapType& PsoHashMap,
else
{
RenderTargetBlendDesc& RT0 = PSOCreateInfo.GraphicsPipeline.BlendDesc.RenderTargets[0];
if (IsTransmissionComposite)
{
GraphicsPipeline.DepthStencilDesc.DepthWriteEnable = False;
}

if (AlphaMode == ALPHA_MODE_OPAQUE ||
AlphaMode == ALPHA_MODE_MASK)
{
Expand Down Expand Up @@ -2189,7 +2220,7 @@ IPipelineState* PBR_Renderer::GetPSO(PsoHashMapType& PsoHashMap,
}
if (!m_Settings.EnableTransmission)
{
Flags &= ~PSO_FLAG_ENABLE_TRANSMISSION;
Flags &= ~(PSO_FLAG_ENABLE_TRANSMISSION | PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE);
}
if (!m_Settings.EnableVolume)
{
Expand Down Expand Up @@ -2230,7 +2261,7 @@ IPipelineState* PBR_Renderer::GetPSO(PsoHashMapType& PsoHashMap,
}
if ((Flags & PSO_FLAG_ENABLE_TRANSMISSION) == 0)
{
Flags &= ~PSO_FLAG_USE_TRANSMISSION_MAP;
Flags &= ~(PSO_FLAG_USE_TRANSMISSION_MAP | PSO_FLAG_ENABLE_TRANSMISSION_COMPOSITE);
}
if ((Flags & PSO_FLAG_ENABLE_VOLUME) == 0)
{
Expand Down
Loading