From 88f2a4d903d9048b455d20aea6cea82216ec13f5 Mon Sep 17 00:00:00 2001 From: DavidWyand-GG Date: Thu, 24 Oct 2013 00:28:13 -0400 Subject: [PATCH] Viewport fix for PostFX and SSAO - General fix for PostFX render targets to properly support the GFX viewport setting. This is an opt-in change through the use of the new mTargetViewport property as most PostFX run fine with their assumption of the viewport being the whole rendering target. - The SSAO PostFX has been modified to use the new mTargetViewport property. This allows correct rendering in a side-by-side view such as with the Oculus Rift, or any other constrained viewport rendering. --- Engine/source/postFx/postEffect.cpp | 66 ++++++++++++++++++- Engine/source/postFx/postEffect.h | 1 + Engine/source/postFx/postEffectCommon.h | 14 ++++ .../game/core/scripts/client/postFx/ssao.cs | 1 + .../game/core/scripts/client/postFx/ssao.cs | 1 + 5 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Engine/source/postFx/postEffect.cpp b/Engine/source/postFx/postEffect.cpp index fdc7958f5..ff83997eb 100644 --- a/Engine/source/postFx/postEffect.cpp +++ b/Engine/source/postFx/postEffect.cpp @@ -112,6 +112,14 @@ ImplementEnumType( PFXTargetClear, { PFXTargetClear_OnDraw, "PFXTargetClear_OnDraw", "Clear before every draw.\n" }, EndImplementEnumType; +ImplementEnumType( PFXTargetViewport, + "Specifies how the viewport should be set up for a PostEffect's target.\n" + "@note Applies to both the diffuse target and the depth target (if defined).\n" + "@ingroup Rendering\n\n") + { PFXTargetViewport_TargetSize, "PFXTargetViewport_TargetSize", "Set viewport to match target size (default).\n" }, + { PFXTargetViewport_GFXViewport, "PFXTargetViewport_GFXViewport", "Use the current GFX viewport (scaled to match target size).\n" }, +EndImplementEnumType; + GFXImplementVertexFormat( PFXVertex ) { @@ -235,6 +243,7 @@ PostEffect::PostEffect() mStateBlockData( NULL ), mAllowReflectPass( false ), mTargetClear( PFXTargetClear_None ), + mTargetViewport( PFXTargetViewport_TargetSize ), mTargetScale( Point2F::One ), mTargetSize( Point2I::Zero ), mTargetFormat( GFXFormatR8G8B8A8 ), @@ -312,6 +321,9 @@ void PostEffect::initPersistFields() addField( "targetClear", TYPEID< PFXTargetClear >(), Offset( mTargetClear, PostEffect ), "Describes when the target texture should be cleared." ); + addField( "targetViewport", TYPEID< PFXTargetViewport >(), Offset( mTargetViewport, PostEffect ), + "Specifies how the viewport should be set up for a target texture." ); + addField( "texture", TypeImageFilename, Offset( mTexFilename, PostEffect ), NumTextures, "Input textures to this effect ( samplers ).\n" "@see PFXTextureIdentifiers" ); @@ -927,7 +939,23 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg if ( mTargetClear == PFXTargetClear_OnCreate ) *outClearTarget = true; - mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); + if(mTargetViewport == PFXTargetViewport_GFXViewport) + { + // We may need to scale the GFX viewport to fit within + // our target texture size + GFXTarget *oldTarget = GFX->getActiveRenderTarget(); + const Point2I &oldTargetSize = oldTarget->getSize(); + Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); + + const RectI viewport = GFX->getViewport(); + + mNamedTarget.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); + } + else + { + // PFXTargetViewport_TargetSize + mNamedTarget.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); + } } } else @@ -973,7 +1001,23 @@ void PostEffect::_setupTarget( const SceneRenderState *state, bool *outClearTarg if ( mTargetClear == PFXTargetClear_OnCreate ) *outClearTarget = true; - mNamedTargetDepthStencil.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); + if(mTargetViewport == PFXTargetViewport_GFXViewport) + { + // We may need to scale the GFX viewport to fit within + // our target texture size + GFXTarget *oldTarget = GFX->getActiveRenderTarget(); + const Point2I &oldTargetSize = oldTarget->getSize(); + Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); + + const RectI viewport = GFX->getViewport(); + + mNamedTargetDepthStencil.setViewport( RectI( viewport.point.x*scale.x, viewport.point.y*scale.y, viewport.extent.x*scale.x, viewport.extent.y*scale.y ) ); + } + else + { + // PFXTargetViewport_TargetSize + mNamedTargetDepthStencil.setViewport( RectI( 0, 0, targetSize.x, targetSize.y ) ); + } } } else @@ -1049,6 +1093,8 @@ void PostEffect::process( const SceneRenderState *state, bool clearTarget = false; _setupTarget( state, &clearTarget ); + RectI oldViewport = GFX->getViewport(); + if ( mTargetTex || mTargetDepthStencil ) { @@ -1064,6 +1110,8 @@ void PostEffect::process( const SceneRenderState *state, GFX->getActiveRenderTarget()->preserve(); #endif + GFXTarget *oldTarget = GFX->getActiveRenderTarget(); + GFX->pushActiveRenderTarget(); mTarget->attachTexture( GFXTextureTarget::Color0, mTargetTex ); @@ -1074,6 +1122,20 @@ void PostEffect::process( const SceneRenderState *state, mTarget->attachTexture( GFXTextureTarget::DepthStencil, mTargetDepthStencil ); GFX->setActiveRenderTarget( mTarget ); + + // The setActiveRenderTarget() called above will change the viewport to cover the + // entire target area. Restore the viewport as necessary. + if(mNamedTarget.isRegistered()) + { + GFX->setViewport(mNamedTarget.getViewport()); + } + else if(mTargetViewport == PFXTargetViewport_GFXViewport) + { + const Point2I &oldTargetSize = oldTarget->getSize(); + const Point2I &targetSize = mTarget->getSize(); + Point2F scale(targetSize.x / F32(oldTargetSize.x), targetSize.y / F32(oldTargetSize.y)); + GFX->setViewport( RectI( oldViewport.point.x*scale.x, oldViewport.point.y*scale.y, oldViewport.extent.x*scale.x, oldViewport.extent.y*scale.y ) ); + } } if ( clearTarget ) diff --git a/Engine/source/postFx/postEffect.h b/Engine/source/postFx/postEffect.h index 71ee725e8..8208a8e88 100644 --- a/Engine/source/postFx/postEffect.h +++ b/Engine/source/postFx/postEffect.h @@ -170,6 +170,7 @@ protected: PFXRenderTime mRenderTime; PFXTargetClear mTargetClear; + PFXTargetViewport mTargetViewport; String mRenderBin; diff --git a/Engine/source/postFx/postEffectCommon.h b/Engine/source/postFx/postEffectCommon.h index dcbbdda27..fecef5a52 100644 --- a/Engine/source/postFx/postEffectCommon.h +++ b/Engine/source/postFx/postEffectCommon.h @@ -67,6 +67,20 @@ enum PFXTargetClear DefineEnumType( PFXTargetClear ); + +/// PFXTargetViewport specifies how the viewport should be +/// set up for a PostEffect's target. +enum PFXTargetViewport +{ + /// The default viewport set up to match the target size + PFXTargetViewport_TargetSize, + + /// Use the current GFX viewport + PFXTargetViewport_GFXViewport, +}; + +DefineEnumType( PFXTargetViewport ); + /// struct PFXFrameState { diff --git a/Templates/Empty/game/core/scripts/client/postFx/ssao.cs b/Templates/Empty/game/core/scripts/client/postFx/ssao.cs index 69977f352..8b54ce870 100644 --- a/Templates/Empty/game/core/scripts/client/postFx/ssao.cs +++ b/Templates/Empty/game/core/scripts/client/postFx/ssao.cs @@ -190,6 +190,7 @@ singleton PostEffect( SSAOPostFx ) target = "$outTex"; targetScale = "0.5 0.5"; + targetViewport = "PFXTargetViewport_GFXViewport"; singleton PostEffect() { diff --git a/Templates/Full/game/core/scripts/client/postFx/ssao.cs b/Templates/Full/game/core/scripts/client/postFx/ssao.cs index 69977f352..8b54ce870 100644 --- a/Templates/Full/game/core/scripts/client/postFx/ssao.cs +++ b/Templates/Full/game/core/scripts/client/postFx/ssao.cs @@ -190,6 +190,7 @@ singleton PostEffect( SSAOPostFx ) target = "$outTex"; targetScale = "0.5 0.5"; + targetViewport = "PFXTargetViewport_GFXViewport"; singleton PostEffect() {