Formalize camera frame composition stages
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
#include <XCEngine/Rendering/RenderPass.h>
|
||||
#include <XCEngine/Rendering/RenderSurface.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Components {
|
||||
class CameraComponent;
|
||||
@@ -13,6 +16,53 @@ class Scene;
|
||||
|
||||
namespace Rendering {
|
||||
|
||||
enum class CameraFrameStage : uint8_t {
|
||||
PreScenePasses,
|
||||
ShadowCaster,
|
||||
DepthOnly,
|
||||
MainScene,
|
||||
ObjectId,
|
||||
PostScenePasses,
|
||||
OverlayPasses
|
||||
};
|
||||
|
||||
struct CameraFrameStageInfo {
|
||||
CameraFrameStage stage = CameraFrameStage::MainScene;
|
||||
const char* name = "";
|
||||
bool runtimeStage = true;
|
||||
};
|
||||
|
||||
inline constexpr std::array<CameraFrameStageInfo, 7> kOrderedCameraFrameStages = {{
|
||||
{ CameraFrameStage::PreScenePasses, "PreScenePasses", false },
|
||||
{ CameraFrameStage::ShadowCaster, "ShadowCaster", true },
|
||||
{ CameraFrameStage::DepthOnly, "DepthOnly", true },
|
||||
{ CameraFrameStage::MainScene, "MainScene", true },
|
||||
{ CameraFrameStage::ObjectId, "ObjectId", false },
|
||||
{ CameraFrameStage::PostScenePasses, "PostScenePasses", false },
|
||||
{ CameraFrameStage::OverlayPasses, "OverlayPasses", false }
|
||||
}};
|
||||
|
||||
inline constexpr const char* GetCameraFrameStageName(CameraFrameStage stage) {
|
||||
switch (stage) {
|
||||
case CameraFrameStage::PreScenePasses:
|
||||
return "PreScenePasses";
|
||||
case CameraFrameStage::ShadowCaster:
|
||||
return "ShadowCaster";
|
||||
case CameraFrameStage::DepthOnly:
|
||||
return "DepthOnly";
|
||||
case CameraFrameStage::MainScene:
|
||||
return "MainScene";
|
||||
case CameraFrameStage::ObjectId:
|
||||
return "ObjectId";
|
||||
case CameraFrameStage::PostScenePasses:
|
||||
return "PostScenePasses";
|
||||
case CameraFrameStage::OverlayPasses:
|
||||
return "OverlayPasses";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct ScenePassRenderRequest {
|
||||
RenderSurface surface;
|
||||
RenderClearFlags clearFlags = RenderClearFlags::Depth;
|
||||
@@ -93,6 +143,55 @@ struct CameraRenderRequest {
|
||||
RenderPassSequence* postScenePasses = nullptr;
|
||||
RenderPassSequence* overlayPasses = nullptr;
|
||||
|
||||
bool HasFrameStage(CameraFrameStage stage) const {
|
||||
switch (stage) {
|
||||
case CameraFrameStage::PreScenePasses:
|
||||
return preScenePasses != nullptr;
|
||||
case CameraFrameStage::ShadowCaster:
|
||||
return shadowCaster.IsRequested() || directionalShadow.IsValid();
|
||||
case CameraFrameStage::DepthOnly:
|
||||
return depthOnly.IsRequested();
|
||||
case CameraFrameStage::MainScene:
|
||||
return true;
|
||||
case CameraFrameStage::ObjectId:
|
||||
return objectId.IsRequested();
|
||||
case CameraFrameStage::PostScenePasses:
|
||||
return postScenePasses != nullptr;
|
||||
case CameraFrameStage::OverlayPasses:
|
||||
return overlayPasses != nullptr;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RenderPassSequence* GetPassSequence(CameraFrameStage stage) const {
|
||||
switch (stage) {
|
||||
case CameraFrameStage::PreScenePasses:
|
||||
return preScenePasses;
|
||||
case CameraFrameStage::PostScenePasses:
|
||||
return postScenePasses;
|
||||
case CameraFrameStage::OverlayPasses:
|
||||
return overlayPasses;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const ScenePassRenderRequest* GetScenePassRequest(CameraFrameStage stage) const {
|
||||
switch (stage) {
|
||||
case CameraFrameStage::ShadowCaster:
|
||||
return &shadowCaster;
|
||||
case CameraFrameStage::DepthOnly:
|
||||
return &depthOnly;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const ObjectIdRenderRequest* GetObjectIdRequest(CameraFrameStage stage) const {
|
||||
return stage == CameraFrameStage::ObjectId ? &objectId : nullptr;
|
||||
}
|
||||
|
||||
bool IsValid() const {
|
||||
return scene != nullptr &&
|
||||
camera != nullptr &&
|
||||
|
||||
@@ -151,6 +151,77 @@ private:
|
||||
bool m_failed = false;
|
||||
};
|
||||
|
||||
struct CameraFrameExecutionState {
|
||||
RenderPipeline* pipeline = nullptr;
|
||||
RenderPass* objectIdPass = nullptr;
|
||||
RenderPass* depthOnlyPass = nullptr;
|
||||
RenderPass* shadowCasterPass = nullptr;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> preScenePasses;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> postScenePasses;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> overlayPasses;
|
||||
};
|
||||
|
||||
bool ExecutePassSequenceStage(
|
||||
std::unique_ptr<ScopedInitializedPassSequence>& activeSequence,
|
||||
RenderPassSequence* sequence,
|
||||
const RenderContext& context,
|
||||
const RenderPassContext& passContext) {
|
||||
activeSequence = std::make_unique<ScopedInitializedPassSequence>(sequence, context);
|
||||
return activeSequence->IsReady() && activeSequence->Execute(passContext);
|
||||
}
|
||||
|
||||
bool ExecuteFrameStage(
|
||||
CameraFrameStage stage,
|
||||
const CameraRenderRequest& request,
|
||||
const ShadowCasterRenderRequest& resolvedShadowCaster,
|
||||
const RenderPassContext& passContext,
|
||||
CameraFrameExecutionState& executionState) {
|
||||
switch (stage) {
|
||||
case CameraFrameStage::PreScenePasses:
|
||||
return ExecutePassSequenceStage(
|
||||
executionState.preScenePasses,
|
||||
request.GetPassSequence(stage),
|
||||
request.context,
|
||||
passContext);
|
||||
case CameraFrameStage::ShadowCaster:
|
||||
return ExecuteScenePassRequest(
|
||||
executionState.shadowCasterPass,
|
||||
resolvedShadowCaster,
|
||||
request.context,
|
||||
passContext.sceneData);
|
||||
case CameraFrameStage::DepthOnly:
|
||||
return ExecuteScenePassRequest(
|
||||
executionState.depthOnlyPass,
|
||||
request.depthOnly,
|
||||
request.context,
|
||||
passContext.sceneData);
|
||||
case CameraFrameStage::MainScene:
|
||||
return executionState.pipeline != nullptr &&
|
||||
executionState.pipeline->Render(request.context, request.surface, passContext.sceneData);
|
||||
case CameraFrameStage::ObjectId:
|
||||
return !request.objectId.IsRequested() ||
|
||||
ExecuteStandalonePass(
|
||||
executionState.objectIdPass,
|
||||
request.context,
|
||||
request.objectId.surface,
|
||||
passContext.sceneData);
|
||||
case CameraFrameStage::PostScenePasses:
|
||||
return ExecutePassSequenceStage(
|
||||
executionState.postScenePasses,
|
||||
request.GetPassSequence(stage),
|
||||
request.context,
|
||||
passContext);
|
||||
case CameraFrameStage::OverlayPasses:
|
||||
return ExecutePassSequenceStage(
|
||||
executionState.overlayPasses,
|
||||
request.GetPassSequence(stage),
|
||||
request.context,
|
||||
passContext);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RenderDirectionalShadowData BuildDirectionalShadowData(
|
||||
const DirectionalShadowRenderPlan& plan,
|
||||
RHI::RHIResourceView* shadowMapView) {
|
||||
@@ -352,49 +423,26 @@ bool CameraRenderer::ExecuteRenderPlan(
|
||||
request.surface,
|
||||
sceneData
|
||||
};
|
||||
CameraFrameExecutionState executionState = {};
|
||||
executionState.pipeline = m_pipeline.get();
|
||||
executionState.objectIdPass = m_objectIdPass.get();
|
||||
executionState.depthOnlyPass = m_depthOnlyPass.get();
|
||||
executionState.shadowCasterPass = m_shadowCasterPass.get();
|
||||
|
||||
ScopedInitializedPassSequence preScenePasses(request.preScenePasses, request.context);
|
||||
if (!preScenePasses.IsReady() || !preScenePasses.Execute(passContext)) {
|
||||
return false;
|
||||
}
|
||||
for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) {
|
||||
if (!request.HasFrameStage(stageInfo.stage) &&
|
||||
stageInfo.stage != CameraFrameStage::MainScene) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ExecuteScenePassRequest(
|
||||
m_shadowCasterPass.get(),
|
||||
resolvedShadowCaster,
|
||||
request.context,
|
||||
sceneData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ExecuteScenePassRequest(
|
||||
m_depthOnlyPass.get(),
|
||||
request.depthOnly,
|
||||
request.context,
|
||||
sceneData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_pipeline->Render(request.context, request.surface, sceneData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (request.objectId.IsRequested() &&
|
||||
!ExecuteStandalonePass(
|
||||
m_objectIdPass.get(),
|
||||
request.context,
|
||||
request.objectId.surface,
|
||||
sceneData)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedInitializedPassSequence postScenePasses(request.postScenePasses, request.context);
|
||||
if (!postScenePasses.IsReady() || !postScenePasses.Execute(passContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedInitializedPassSequence overlayPasses(request.overlayPasses, request.context);
|
||||
if (!overlayPasses.IsReady() || !overlayPasses.Execute(passContext)) {
|
||||
return false;
|
||||
if (!ExecuteFrameStage(
|
||||
stageInfo.stage,
|
||||
request,
|
||||
resolvedShadowCaster,
|
||||
passContext,
|
||||
executionState)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user