Formalize camera frame composition stages

This commit is contained in:
2026-04-05 22:43:48 +08:00
parent 5342e447af
commit 58f97c416b
3 changed files with 306 additions and 41 deletions

View File

@@ -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 &&

View File

@@ -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;