Add forward shadow receiving support
This commit is contained in:
@@ -283,6 +283,13 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
|
||||
|
||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||
|
||||
if (sceneData.lighting.HasMainDirectionalShadow()) {
|
||||
commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::DepthWrite,
|
||||
RHI::ResourceStates::PixelShaderResource);
|
||||
}
|
||||
|
||||
RHI::RHIPipelineState* currentPipelineState = nullptr;
|
||||
for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) {
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
@@ -303,6 +310,13 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
|
||||
DrawVisibleItem(context, sceneData, visibleItem);
|
||||
}
|
||||
|
||||
if (sceneData.lighting.HasMainDirectionalShadow()) {
|
||||
commandList->TransitionBarrier(
|
||||
sceneData.lighting.mainDirectionalShadow.shadowMap,
|
||||
RHI::ResourceStates::PixelShaderResource,
|
||||
RHI::ResourceStates::DepthWrite);
|
||||
}
|
||||
|
||||
if (surface.IsAutoTransitionEnabled()) {
|
||||
commandList->EndRenderPass();
|
||||
for (RHI::RHIResourceView* renderTarget : renderTargets) {
|
||||
@@ -370,6 +384,13 @@ bool BuiltinForwardPipeline::CreatePipelineResources(const RenderContext& contex
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::SamplerDesc shadowSamplerDesc = samplerDesc;
|
||||
shadowSamplerDesc.filter = static_cast<uint32_t>(RHI::FilterMode::Point);
|
||||
m_shadowSampler = context.device->CreateSampler(shadowSamplerDesc);
|
||||
if (m_shadowSampler == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char whitePixel[4] = { 255, 255, 255, 255 };
|
||||
RHI::TextureDesc textureDesc = {};
|
||||
textureDesc.width = 1;
|
||||
@@ -438,6 +459,12 @@ void BuiltinForwardPipeline::DestroyPipelineResources() {
|
||||
m_sampler = nullptr;
|
||||
}
|
||||
|
||||
if (m_shadowSampler != nullptr) {
|
||||
m_shadowSampler->Shutdown();
|
||||
delete m_shadowSampler;
|
||||
m_shadowSampler = nullptr;
|
||||
}
|
||||
|
||||
m_device = nullptr;
|
||||
m_initialized = false;
|
||||
m_builtinForwardShader.Reset();
|
||||
@@ -527,8 +554,11 @@ BuiltinForwardPipeline::PassResourceLayout* BuiltinForwardPipeline::GetOrCreateP
|
||||
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.material = bindingPlan.material;
|
||||
passLayout.shadowReceiver = bindingPlan.shadowReceiver;
|
||||
passLayout.baseColorTexture = bindingPlan.baseColorTexture;
|
||||
passLayout.linearClampSampler = bindingPlan.linearClampSampler;
|
||||
passLayout.shadowMapTexture = bindingPlan.shadowMapTexture;
|
||||
passLayout.shadowMapSampler = bindingPlan.shadowMapSampler;
|
||||
|
||||
if (!passLayout.perObject.IsValid()) {
|
||||
return failLayout("BuiltinForwardPipeline requires a PerObject resource binding");
|
||||
@@ -672,14 +702,33 @@ RHI::RHIDescriptorSet* BuiltinForwardPipeline::GetOrCreateStaticDescriptorSet(
|
||||
}
|
||||
|
||||
if (passLayout.setLayouts[setIndex].usesSampler) {
|
||||
if (m_sampler == nullptr ||
|
||||
!passLayout.linearClampSampler.IsValid() ||
|
||||
passLayout.linearClampSampler.set != setIndex) {
|
||||
RHI::RHISampler* sampler = nullptr;
|
||||
Core::uint32 binding = 0;
|
||||
|
||||
if (passLayout.setLayouts[setIndex].usesLinearClampSampler) {
|
||||
sampler = m_sampler;
|
||||
if (!passLayout.linearClampSampler.IsValid() ||
|
||||
passLayout.linearClampSampler.set != setIndex) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
binding = passLayout.linearClampSampler.binding;
|
||||
} else if (passLayout.setLayouts[setIndex].usesShadowMapSampler) {
|
||||
sampler = m_shadowSampler;
|
||||
if (!passLayout.shadowMapSampler.IsValid() ||
|
||||
passLayout.shadowMapSampler.set != setIndex) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
binding = passLayout.shadowMapSampler.binding;
|
||||
}
|
||||
|
||||
if (sampler == nullptr) {
|
||||
DestroyOwnedDescriptorSet(descriptorSet);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
descriptorSet.set->UpdateSampler(passLayout.linearClampSampler.binding, m_sampler);
|
||||
descriptorSet.set->UpdateSampler(binding, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,7 +743,9 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
|
||||
Core::uint64 objectId,
|
||||
const Resources::Material* material,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
RHI::RHIResourceView* textureView) {
|
||||
const ShadowReceiverConstants& shadowReceiverConstants,
|
||||
RHI::RHIResourceView* baseColorTextureView,
|
||||
RHI::RHIResourceView* shadowMapTextureView) {
|
||||
DynamicDescriptorSetKey key = {};
|
||||
key.passLayout = passLayoutKey;
|
||||
key.setIndex = setIndex;
|
||||
@@ -709,35 +760,61 @@ BuiltinForwardPipeline::CachedDescriptorSet* BuiltinForwardPipeline::GetOrCreate
|
||||
}
|
||||
|
||||
const Core::uint64 materialVersion = material != nullptr ? material->GetChangeVersion() : 0;
|
||||
if ((setLayout.usesMaterial || setLayout.usesTexture) &&
|
||||
(cachedDescriptorSet.materialVersion != materialVersion ||
|
||||
cachedDescriptorSet.textureView != textureView)) {
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() || passLayout.material.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!materialConstants.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() || passLayout.material.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!materialConstants.IsValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.materialVersion != materialVersion) {
|
||||
cachedDescriptorSet.descriptorSet.set->WriteConstant(
|
||||
passLayout.material.binding,
|
||||
materialConstants.data,
|
||||
materialConstants.size);
|
||||
}
|
||||
|
||||
if (setLayout.usesTexture) {
|
||||
if (textureView == nullptr ||
|
||||
!passLayout.baseColorTexture.IsValid() ||
|
||||
passLayout.baseColorTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
cachedDescriptorSet.descriptorSet.set->Update(passLayout.baseColorTexture.binding, textureView);
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.textureView = textureView;
|
||||
}
|
||||
|
||||
if (setLayout.usesShadowReceiver) {
|
||||
if (!passLayout.shadowReceiver.IsValid() || passLayout.shadowReceiver.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
cachedDescriptorSet.descriptorSet.set->WriteConstant(
|
||||
passLayout.shadowReceiver.binding,
|
||||
&shadowReceiverConstants,
|
||||
sizeof(shadowReceiverConstants));
|
||||
}
|
||||
|
||||
if (setLayout.usesBaseColorTexture) {
|
||||
if (baseColorTextureView == nullptr ||
|
||||
!passLayout.baseColorTexture.IsValid() ||
|
||||
passLayout.baseColorTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.baseColorTextureView != baseColorTextureView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.baseColorTexture.binding,
|
||||
baseColorTextureView);
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesShadowMapTexture) {
|
||||
if (shadowMapTextureView == nullptr ||
|
||||
!passLayout.shadowMapTexture.IsValid() ||
|
||||
passLayout.shadowMapTexture.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
if (cachedDescriptorSet.shadowMapTextureView != shadowMapTextureView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.shadowMapTexture.binding,
|
||||
shadowMapTextureView);
|
||||
}
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.baseColorTextureView = baseColorTextureView;
|
||||
cachedDescriptorSet.shadowMapTextureView = shadowMapTextureView;
|
||||
|
||||
return &cachedDescriptorSet;
|
||||
}
|
||||
|
||||
@@ -772,8 +849,11 @@ void BuiltinForwardPipeline::DestroyPassResourceLayout(PassResourceLayout& passL
|
||||
passLayout.descriptorSetCount = 0;
|
||||
passLayout.perObject = {};
|
||||
passLayout.material = {};
|
||||
passLayout.shadowReceiver = {};
|
||||
passLayout.baseColorTexture = {};
|
||||
passLayout.linearClampSampler = {};
|
||||
passLayout.shadowMapTexture = {};
|
||||
passLayout.shadowMapSampler = {};
|
||||
}
|
||||
|
||||
const Resources::Texture* BuiltinForwardPipeline::ResolveTexture(const Resources::Material* material) const {
|
||||
@@ -833,6 +913,17 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
1.0f)
|
||||
: Math::Vector4::Zero()
|
||||
};
|
||||
const ShadowReceiverConstants shadowReceiverConstants = {
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.viewProjection
|
||||
: Math::Matrix4x4::Identity(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowParams
|
||||
: Math::Vector4::Zero(),
|
||||
sceneData.lighting.HasMainDirectionalShadow()
|
||||
? Math::Vector4(1.0f, 0.0f, 0.0f, 0.0f)
|
||||
: Math::Vector4::Zero()
|
||||
};
|
||||
|
||||
const Resources::Material* material = ResolveMaterial(visibleItem);
|
||||
const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(material);
|
||||
@@ -849,8 +940,15 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* textureView = ResolveTextureView(visibleItem);
|
||||
if (passLayout->baseColorTexture.IsValid() && textureView == nullptr) {
|
||||
RHI::RHIResourceView* baseColorTextureView = ResolveTextureView(visibleItem);
|
||||
if (passLayout->baseColorTexture.IsValid() && baseColorTextureView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* shadowMapTextureView = sceneData.lighting.HasMainDirectionalShadow()
|
||||
? sceneData.lighting.mainDirectionalShadow.shadowMap
|
||||
: m_fallbackTextureView;
|
||||
if (passLayout->shadowMapTexture.IsValid() && shadowMapTextureView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -887,13 +985,16 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout->setLayouts[setIndex];
|
||||
RHI::RHIDescriptorSet* descriptorSet = nullptr;
|
||||
|
||||
if (setLayout.usesPerObject || setLayout.usesMaterial || setLayout.usesTexture) {
|
||||
if (setLayout.usesPerObject ||
|
||||
setLayout.usesMaterial ||
|
||||
setLayout.usesShadowReceiver ||
|
||||
setLayout.usesTexture) {
|
||||
const Core::uint64 objectId =
|
||||
(setLayout.usesPerObject && visibleItem.gameObject != nullptr)
|
||||
? visibleItem.gameObject->GetID()
|
||||
: 0;
|
||||
const Resources::Material* materialKey =
|
||||
(setLayout.usesMaterial || setLayout.usesTexture) ? material : nullptr;
|
||||
(setLayout.usesMaterial || setLayout.usesBaseColorTexture) ? material : nullptr;
|
||||
|
||||
CachedDescriptorSet* cachedDescriptorSet = GetOrCreateDynamicDescriptorSet(
|
||||
passLayoutKey,
|
||||
@@ -903,7 +1004,9 @@ bool BuiltinForwardPipeline::DrawVisibleItem(
|
||||
objectId,
|
||||
materialKey,
|
||||
materialConstants,
|
||||
textureView);
|
||||
shadowReceiverConstants,
|
||||
baseColorTextureView,
|
||||
shadowMapTextureView);
|
||||
if (cachedDescriptorSet == nullptr || cachedDescriptorSet->descriptorSet.set == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user