29 bool formatsEqual(
const std::vector<PixelFormat>& a,
const std::vector<PixelFormat>& b)
37 CameraComponent* cameraComponent,
const std::shared_ptr<RenderTarget>& targetRenderTarget)
38 :
RenderPass(
device), _layerComposition(layerComposition), _scene(scene), _renderer(renderer),
39 _cameraComponent(cameraComponent), _targetRenderTarget(targetRenderTarget), _sourceActions(sourceActions)
49 if (_cameraComponent) {
50 const auto& taa = _cameraComponent->taa();
51 const auto& dof = _cameraComponent->dof();
52 const auto& ssao = _cameraComponent->ssao();
53 const auto& rendering = _cameraComponent->rendering();
75 setupRenderPasses(_options);
85 if (
const auto gd =
device()) {
88 if (_sceneDepthTexture && gd->sceneDepthMap() == _sceneDepthTexture.get()) {
89 gd->setSceneDepthMap(
nullptr);
93 if (_ssaoPass && gd->ssaoForwardTexture() == _ssaoPass->ssaoTexture()) {
94 gd->setSsaoForwardTexture(
nullptr);
102 _sceneTexture.reset();
103 _sceneDepthTexture.reset();
104 _sceneTextureHalf.reset();
105 _sceneRenderTarget.reset();
106 _sceneHalfRenderTarget.reset();
112 _colorGrabPass.reset();
113 _scenePassTransparent.reset();
116 _scenePassHalf.reset();
119 _composePass.reset();
122 _sceneTextureResolved =
nullptr;
123 _ownedActions.clear();
137 const auto& current = _options;
138 return options.
ssaoType != current.ssaoType ||
141 options.
samples != current.samples ||
142 options.
stencil != current.stencil ||
149 !formatsEqual(options.
formats, current.formats);
160 _options = sanitized;
161 if (!_sceneTexture) {
162 setupRenderPasses(_options);
168 const std::shared_ptr<RenderTarget>& targetRenderTarget)
170 _sourceActions = sourceActions;
171 _layerComposition = layerComposition;
173 _renderer = renderer;
174 _targetRenderTarget = targetRenderTarget;
182 _ownedActions.clear();
186 _colorGrabPass.reset();
187 _scenePassTransparent.reset();
189 _composePass.reset();
190 _sceneTextureResolved =
nullptr;
196 if (_cameraComponent) {
198 const auto& taa = _cameraComponent->taa();
199 const auto& dof = _cameraComponent->dof();
200 const auto& ssao = _cameraComponent->ssao();
201 const auto& rendering = _cameraComponent->rendering();
225 _options = sanitized;
226 setupRenderPasses(_options);
229 _options = sanitized;
233 createPasses(_options);
235 for (
const auto& pass : collectPasses()) {
244 _renderTargetScale = value;
246 _sceneOptions->scaleX = value;
247 _sceneOptions->scaleY = value;
251 std::shared_ptr<RenderTarget> RenderPassCameraFrame::createRenderTarget(
const std::string& name,
const bool depth,
252 const bool stencil,
const int samples)
const
259 TextureOptions textureOptions;
260 textureOptions.name = name;
261 textureOptions.width = 4;
262 textureOptions.height = 4;
263 textureOptions.format = _hdrFormat;
264 textureOptions.mipmaps =
false;
267 auto colorTexture = std::make_shared<Texture>(gd.get(), textureOptions);
271 RenderTargetOptions rtOptions;
272 rtOptions.graphicsDevice = gd.get();
273 rtOptions.colorBuffer = colorTexture.get();
274 rtOptions.depth = depth;
275 rtOptions.stencil = stencil;
276 rtOptions.samples = samples;
277 rtOptions.name = name;
278 return gd->createRenderTarget(rtOptions);
281 std::shared_ptr<RenderAction> RenderPassCameraFrame::cloneActionWithTarget(
const RenderAction* source,
282 const std::shared_ptr<RenderTarget>& renderTarget)
287 auto cloned = std::make_shared<RenderAction>(*source);
292 int RenderPassCameraFrame::findActionIndex(
const int targetLayerId,
const bool targetTransparent,
const int fromIndex)
const
294 for (
int i = std::max(fromIndex, 0); i < static_cast<int>(_sourceActions.size()); ++i) {
295 const auto* action = _sourceActions[i];
296 if (!action || !action->layer || action->layer->id() ==
LAYERID_DEPTH) {
299 if (action->layer->id() == targetLayerId && action->transparent == targetTransparent) {
306 int RenderPassCameraFrame::appendActionsToPass(
const std::shared_ptr<RenderPassForward>& pass,
const int fromIndex,
307 const int toIndex,
const std::shared_ptr<RenderTarget>& target,
const bool firstLayerClears)
309 if (!pass || fromIndex < 0 || toIndex < fromIndex || _sourceActions.empty()) {
310 return fromIndex - 1;
314 int lastAddedIndex = fromIndex - 1;
315 const int clampedTo = std::min(toIndex,
static_cast<int>(_sourceActions.size()) - 1);
316 for (
int i = fromIndex; i <= clampedTo; ++i) {
317 auto* action = _sourceActions[i];
318 if (!action || !action->layer || action->layer->id() ==
LAYERID_DEPTH) {
321 auto cloned = cloneActionWithTarget(action, target);
330 if (isFirst && !firstLayerClears) {
331 cloned->setupClears(
nullptr, action->layer);
335 pass->addRenderAction(cloned.get());
336 _ownedActions.push_back(cloned);
339 return lastAddedIndex;
344 if (!_cameraComponent || !_renderer || !_scene) {
355 _sceneHalfEnabled = _bloomEnabled || options.dofEnabled;
362 const auto [initW, initH] = gd->size();
364 TextureOptions colorOpts;
365 colorOpts.name =
"SceneColor";
366 colorOpts.width = std::max(initW, 1);
367 colorOpts.height = std::max(initH, 1);
368 colorOpts.format = _hdrFormat;
369 colorOpts.mipmaps =
false;
372 _sceneTexture = std::make_shared<Texture>(gd.get(), colorOpts);
377 TextureOptions sceneDepthOptions;
378 sceneDepthOptions.name =
"CameraFrameSceneDepth";
379 sceneDepthOptions.width = std::max(_sceneTexture ?
static_cast<int>(_sceneTexture->width()) : 1, 1);
380 sceneDepthOptions.height = std::max(_sceneTexture ?
static_cast<int>(_sceneTexture->height()) : 1, 1);
382 sceneDepthOptions.mipmaps =
false;
385 _sceneDepthTexture = std::make_shared<Texture>(gd.get(), sceneDepthOptions);
389 RenderTargetOptions sceneTargetOptions;
390 sceneTargetOptions.graphicsDevice = gd.get();
391 sceneTargetOptions.colorBuffer = _sceneTexture.get();
392 sceneTargetOptions.depthBuffer = _sceneDepthTexture.get();
393 sceneTargetOptions.stencil = options.stencil;
394 sceneTargetOptions.samples = options.samples;
395 sceneTargetOptions.name =
"CameraFrameSceneTarget";
396 _sceneRenderTarget = gd->createRenderTarget(sceneTargetOptions);
398 if (_sceneHalfEnabled) {
400 TextureOptions halfOpts;
401 halfOpts.name =
"SceneColorHalf";
404 halfOpts.format = _hdrFormat;
405 halfOpts.mipmaps =
false;
408 _sceneTextureHalf = std::make_shared<Texture>(gd.get(), halfOpts);
412 RenderTargetOptions halfTargetOptions;
413 halfTargetOptions.graphicsDevice = gd.get();
414 halfTargetOptions.colorBuffer = _sceneTextureHalf.get();
415 halfTargetOptions.depth =
false;
416 halfTargetOptions.stencil =
false;
417 halfTargetOptions.samples = 1;
418 halfTargetOptions.name =
"SceneColorHalf";
419 _sceneHalfRenderTarget = gd->createRenderTarget(halfTargetOptions);
422 _sceneOptions = std::make_shared<RenderPassOptions>();
423 if (_targetRenderTarget && _targetRenderTarget->colorBuffer()) {
424 _sceneOptions->resizeSource = std::shared_ptr<Texture>(_targetRenderTarget->colorBuffer(), [](Texture*) {});
426 _sceneOptions->scaleX = _renderTargetScale;
427 _sceneOptions->scaleY = _renderTargetScale;
429 createPasses(options);
432 for (
const auto& pass : collectPasses()) {
439 std::vector<std::shared_ptr<RenderPass>> RenderPassCameraFrame::collectPasses()
const
446 return {_prePass, _scenePass, _colorGrabPass, _scenePassTransparent, _ssaoPass, _taaPass, _scenePassHalf,
447 _bloomPass, _dofPass, _composePass, _afterPass};
452 setupScenePrepass(options);
453 setupSsaoPass(options);
454 const auto scenePassesInfo = setupScenePass(options);
455 auto* sceneTextureWithTaa = setupTaaPass(options);
456 setupSceneHalfPass(options, sceneTextureWithTaa);
457 setupBloomPass(options, _sceneTextureHalf.get());
458 setupDofPass(options, _sceneTexture.get(), _sceneTextureHalf.get());
459 setupComposePass(options);
460 setupAfterPass(options, scenePassesInfo);
465 if (options.prepassEnabled) {
466 _prePass = std::make_shared<RenderPassPrepass>(
device(), _scene, _renderer, _cameraComponent,
467 _sceneDepthTexture.get(), _sceneOptions);
471 RenderPassCameraFrame::ScenePassesInfo RenderPassCameraFrame::setupScenePass(
const CameraFrameOptions& options)
473 ScenePassesInfo info;
474 if (!_layerComposition || !_sceneRenderTarget) {
478 _scenePass = std::make_shared<RenderPassForward>(
device(), _layerComposition, _scene, _renderer);
479 _scenePass->setHdrPass(
true);
480 _scenePass->init(_sceneRenderTarget, _sceneOptions);
482 const int lastLayerId = options.sceneColorMap ? options.lastGrabLayerId : options.lastSceneLayerId;
483 const bool lastLayerTransparent = options.sceneColorMap ? options.lastGrabLayerIsTransparent : options.lastSceneLayerIsTransparent;
484 const int sceneEndIndex = findActionIndex(lastLayerId, lastLayerTransparent, 0);
486 if (sceneEndIndex < 0) {
490 info.lastAddedIndex = appendActionsToPass(_scenePass, 0, sceneEndIndex, _sceneRenderTarget);
491 info.clearRenderTarget =
false;
493 if (options.sceneColorMap) {
494 _colorGrabPass = std::make_shared<RenderPassColorGrab>(
device());
495 _colorGrabPass->setSource(_sceneRenderTarget);
497 const int transparentEndIndex = findActionIndex(options.lastSceneLayerId, options.lastSceneLayerIsTransparent,
498 std::max(info.lastAddedIndex + 1, 0));
499 if (transparentEndIndex >= 0) {
500 _scenePassTransparent = std::make_shared<RenderPassForward>(
device(), _layerComposition, _scene, _renderer);
501 _scenePassTransparent->setHdrPass(
true);
502 _scenePassTransparent->init(_sceneRenderTarget);
503 info.lastAddedIndex = appendActionsToPass(_scenePassTransparent, info.lastAddedIndex + 1, transparentEndIndex,
513 if (options.ssaoType !=
SSAOTYPE_NONE && _sceneTexture && _cameraComponent) {
518 _ssaoPass = std::make_shared<RenderPassSsao>(
device(), _sceneTexture.get(), _cameraComponent, options.ssaoBlurEnabled);
522 const auto& ssao = _cameraComponent->ssao();
523 _ssaoPass->radius = ssao.radius;
524 _ssaoPass->intensity = ssao.intensity;
525 _ssaoPass->power = ssao.power;
526 _ssaoPass->sampleCount = ssao.samples;
527 _ssaoPass->minAngle = ssao.minAngle;
528 _ssaoPass->randomize = ssao.randomize;
529 if (ssao.scale != _ssaoPass->scale()) {
530 _ssaoPass->setScale(ssao.scale);
539 _sceneTextureResolved = _sceneTexture.get();
540 if (options.taaEnabled && _sceneTexture) {
541 _taaPass = _cameraComponent->ensureTaaPass(
device(), _sceneTexture.get());
543 _taaPass->setSourceTexture(_sceneTexture.get());
544 _taaPass->setDepthTexture(_sceneDepthTexture.get());
545 _sceneTextureResolved = _taaPass->historyTexture().get();
548 return _sceneTextureResolved;
554 if (_sceneHalfEnabled && _sceneHalfRenderTarget && _sceneTexture) {
556 if (!_scenePassHalf) {
557 RenderPassDownsample::Options downsampleOptions;
558 downsampleOptions.boxFilter =
true;
559 downsampleOptions.removeInvalid =
true;
560 _scenePassHalf = std::make_shared<RenderPassDownsample>(
device(), _sceneTexture.get(), downsampleOptions);
561 auto passOptions = std::make_shared<RenderPassOptions>();
562 passOptions->resizeSource = std::shared_ptr<Texture>(sourceTexture, [](Texture*) {});
563 passOptions->scaleX = 0.5f;
564 passOptions->scaleY = 0.5f;
565 _scenePassHalf->init(_sceneHalfRenderTarget, passOptions);
566 const Color clearBlack(0.0f, 0.0f, 0.0f, 1.0f);
567 _scenePassHalf->setClearColor(&clearBlack);
570 _scenePassHalf.reset();
577 if (_bloomEnabled && inputTexture) {
583 _bloomPass = std::make_shared<RenderPassBloom>(
device(), inputTexture, _hdrFormat);
599 (void)inputTextureHalf;
605 _composePass = std::make_shared<RenderPassCompose>(
device());
606 _composePass->sceneTexture = _sceneTextureResolved;
607 _composePass->bloomTexture = _bloomPass ? _bloomPass->bloomTexture() :
nullptr;
608 _composePass->bloomIntensity = options.bloomIntensity;
609 _composePass->taaEnabled = options.taaEnabled;
610 _composePass->cocTexture =
nullptr;
611 _composePass->blurTexture =
nullptr;
612 _composePass->blurTextureUpscale =
false;
613 _composePass->dofEnabled = options.dofEnabled;
614 _composePass->ssaoTexture = options.ssaoType ==
SSAOTYPE_COMBINE && _ssaoPass ? _ssaoPass->ssaoTexture() :
nullptr;
615 _composePass->sharpness = options.sharpness;
616 _composePass->toneMapping = _scene ? _scene->toneMapping() :
TONEMAP_LINEAR;
617 _composePass->exposure = _scene ? _scene->exposure() : 1.0f;
620 if (options.dofEnabled && _cameraComponent) {
621 const auto& dof = _cameraComponent->dof();
622 _composePass->depthTexture = _sceneDepthTexture.get();
623 _composePass->dofFocusDistance = dof.focusDistance;
624 _composePass->dofFocusRange = dof.focusRange;
625 _composePass->dofBlurRadius = dof.blurRadius;
626 if (
auto* camera = _cameraComponent->camera()) {
627 _composePass->dofCameraNear = camera->nearClip();
628 _composePass->dofCameraFar = camera->farClip();
633 _composePass->vignetteEnabled = options.vignetteEnabled;
634 _composePass->vignetteInner = options.vignetteInner;
635 _composePass->vignetteOuter = options.vignetteOuter;
636 _composePass->vignetteCurvature = options.vignetteCurvature;
637 _composePass->vignetteIntensity = options.vignetteIntensity;
639 _composePass->init(_targetRenderTarget);
642 void RenderPassCameraFrame::setupAfterPass(
const CameraFrameOptions& options,
const ScenePassesInfo& scenePassesInfo)
645 if (!_layerComposition) {
649 const int fromIndex = scenePassesInfo.lastAddedIndex + 1;
650 if (fromIndex < 0 || fromIndex >=
static_cast<int>(_sourceActions.size())) {
654 _afterPass = std::make_shared<RenderPassForward>(
device(), _layerComposition, _scene, _renderer);
655 _afterPass->init(_targetRenderTarget);
662 const int appended = appendActionsToPass(_afterPass, fromIndex,
static_cast<int>(_sourceActions.size()) - 1, _targetRenderTarget,
664 if (appended < fromIndex) {
679 if (gd && _sceneRenderTarget && !_targetRenderTarget) {
680 const auto [devW, devH] = gd->size();
681 if (devW > 0 && devH > 0 &&
682 (_sceneRenderTarget->width() != devW || _sceneRenderTarget->height() != devH)) {
683 _sceneRenderTarget->resize(devW, devH);
687 if (gd && _sceneDepthTexture) {
688 gd->setSceneDepthMap(_sceneDepthTexture.get());
694 gd->setSsaoForwardTexture(
696 ? _ssaoPass->ssaoTexture() :
nullptr);
699 if (_sceneTexture && _sceneDepthTexture) {
700 assert(_sceneTexture->width() == _sceneDepthTexture->width() &&
701 _sceneTexture->height() == _sceneDepthTexture->height() &&
702 "CameraFrame scene color/depth textures must stay dimension-matched.");
706 _taaPass->setDepthTexture(_sceneDepthTexture.get());
710 auto* resolvedTexture = _sceneTexture.get();
712 auto taaTexture = _taaPass->update();
713 resolvedTexture = _taaPass->historyValid()
714 ? (taaTexture ? taaTexture.get() : _sceneTexture.get())
715 : _sceneTexture.get();
718 _sceneTextureResolved = resolvedTexture;
719 _composePass->sceneTexture = resolvedTexture;
720 if (_scenePassHalf) {
721 _scenePassHalf->setSourceTexture(resolvedTexture);
void setRenderTargetScale(float value)
CameraFrameOptions sanitizeOptions(const CameraFrameOptions &options) const
void updateSourceActions(const std::vector< RenderAction * > &sourceActions, LayerComposition *layerComposition, Scene *scene, Renderer *renderer, const std::shared_ptr< RenderTarget > &targetRenderTarget)
bool needsReset(const CameraFrameOptions &options) const
RenderPassCameraFrame(const std::shared_ptr< GraphicsDevice > &device, LayerComposition *layerComposition, Scene *scene, Renderer *renderer, const std::vector< RenderAction * > &sourceActions, CameraComponent *cameraComponent, const std::shared_ptr< RenderTarget > &targetRenderTarget)
void update(const CameraFrameOptions &options)
void frameUpdate() const override
std::shared_ptr< RenderTarget > renderTarget() const
virtual void frameUpdate() const
std::shared_ptr< GraphicsDevice > device() const
RenderPass(const std::shared_ptr< GraphicsDevice > &device)
void addBeforePass(const std::shared_ptr< RenderPass > &renderPass)
Container for the scene graph, lighting environment, fog, skybox, and layer composition.
GPU texture resource supporting 2D, cubemap, volume, and array formats with mipmap management.
constexpr int LAYERID_DEPTH
constexpr std::string_view SSAOTYPE_NONE
constexpr std::string_view SSAOTYPE_COMBINE
constexpr std::string_view SSAOTYPE_LIGHTING
std::vector< PixelFormat > formats
std::string_view ssaoType