From 39227f15591d48b1c4c105b710fba7f603979f01 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Wed, 20 Apr 2022 10:54:25 +0200 Subject: [PATCH] Improved TAA jittering --- neo/renderer/GLMatrix.cpp | 52 ++++++++++++++++-------------- neo/renderer/GLMatrix.h | 2 +- neo/renderer/RenderBackend.cpp | 37 +++++++++++++++------ neo/renderer/RenderCommon.h | 5 +++ neo/renderer/RenderSystem_init.cpp | 3 +- neo/renderer/tr_frontend_main.cpp | 6 +++- 6 files changed, 67 insertions(+), 38 deletions(-) diff --git a/neo/renderer/GLMatrix.cpp b/neo/renderer/GLMatrix.cpp index ae8d7859..01ccf8b2 100644 --- a/neo/renderer/GLMatrix.cpp +++ b/neo/renderer/GLMatrix.cpp @@ -470,14 +470,14 @@ void ModifyProjectionMatrix( viewDef_t* viewDef, const idPlane& clipPlane ) memcpy( viewDef->projectionMatrix, matrix, sizeof( float ) * 16 ); } -void R_SetupProjectionMatrix( viewDef_t* viewDef ) +void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter ) { // random jittering is usefull when multiple // frames are going to be blended together // for motion blurred anti-aliasing float jitterx, jittery; - if( R_UseTemporalAA() ) + if( R_UseTemporalAA() && doJitter ) { idVec2 jitter = tr.backend.GetCurrentPixelOffset(); jitterx = jitter.x; @@ -521,54 +521,56 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef ) const float yoffset = ( ymax + ymin ) / height; #else - // according to https://www.elopezr.com/temporal-aa-and-the-quest-for-the-holy-trail/ - const float xoffset = jitterx / ( 2.0f * viewWidth ); - const float yoffset = jittery / ( 2.0f * viewHeight ); + // this mimics the logic in the Donut / Feature Demo + const float xoffset = -2.0f * jitterx / ( 1.0f * viewWidth ); + const float yoffset = -2.0f * jittery / ( 1.0f * viewHeight ); #endif // RB: IMPORTANT - the projectionMatrix has a few changes to make it work with Vulkan // for a detailed explanation see https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/ - viewDef->projectionMatrix[0 * 4 + 0] = 2.0f * zNear / width; - viewDef->projectionMatrix[1 * 4 + 0] = 0.0f; - viewDef->projectionMatrix[2 * 4 + 0] = xoffset; - viewDef->projectionMatrix[3 * 4 + 0] = 0.0f; + float* projectionMatrix = doJitter ? viewDef->projectionMatrix : viewDef->unjitteredProjectionMatrix; - viewDef->projectionMatrix[0 * 4 + 1] = 0.0f; + projectionMatrix[0 * 4 + 0] = 2.0f * zNear / width; + projectionMatrix[1 * 4 + 0] = 0.0f; + projectionMatrix[2 * 4 + 0] = xoffset; + projectionMatrix[3 * 4 + 0] = 0.0f; + + projectionMatrix[0 * 4 + 1] = 0.0f; // RB: Y axis now points down the screen #if defined(USE_VULKAN) - viewDef->projectionMatrix[1 * 4 + 1] = -2.0f * zNear / height; + projectionMatrix[1 * 4 + 1] = -2.0f * zNear / height; #else - viewDef->projectionMatrix[1 * 4 + 1] = 2.0f * zNear / height; + projectionMatrix[1 * 4 + 1] = 2.0f * zNear / height; #endif - viewDef->projectionMatrix[2 * 4 + 1] = yoffset; - viewDef->projectionMatrix[3 * 4 + 1] = 0.0f; + projectionMatrix[2 * 4 + 1] = yoffset; + projectionMatrix[3 * 4 + 1] = 0.0f; // this is the far-plane-at-infinity formulation, and // crunches the Z range slightly so w=0 vertexes do not // rasterize right at the wraparound point - viewDef->projectionMatrix[0 * 4 + 2] = 0.0f; - viewDef->projectionMatrix[1 * 4 + 2] = 0.0f; - viewDef->projectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues + projectionMatrix[0 * 4 + 2] = 0.0f; + projectionMatrix[1 * 4 + 2] = 0.0f; + projectionMatrix[2 * 4 + 2] = -0.999f; // adjust value to prevent imprecision issues // RB: was -2.0f * zNear // the transformation into window space has changed from [-1 .. -1] to [0 .. -1] - viewDef->projectionMatrix[3 * 4 + 2] = -1.0f * zNear; + projectionMatrix[3 * 4 + 2] = -1.0f * zNear; - viewDef->projectionMatrix[0 * 4 + 3] = 0.0f; - viewDef->projectionMatrix[1 * 4 + 3] = 0.0f; - viewDef->projectionMatrix[2 * 4 + 3] = -1.0f; - viewDef->projectionMatrix[3 * 4 + 3] = 0.0f; + projectionMatrix[0 * 4 + 3] = 0.0f; + projectionMatrix[1 * 4 + 3] = 0.0f; + projectionMatrix[2 * 4 + 3] = -1.0f; + projectionMatrix[3 * 4 + 3] = 0.0f; if( viewDef->renderView.flipProjection ) { - viewDef->projectionMatrix[1 * 4 + 1] = -viewDef->projectionMatrix[1 * 4 + 1]; - viewDef->projectionMatrix[1 * 4 + 3] = -viewDef->projectionMatrix[1 * 4 + 3]; + projectionMatrix[1 * 4 + 1] = -projectionMatrix[1 * 4 + 1]; + projectionMatrix[1 * 4 + 3] = -projectionMatrix[1 * 4 + 3]; } // SP Begin - if( viewDef->isObliqueProjection ) + if( viewDef->isObliqueProjection && doJitter ) { R_ObliqueProjection( viewDef ); } diff --git a/neo/renderer/GLMatrix.h b/neo/renderer/GLMatrix.h index 60e5fac3..198b8286 100644 --- a/neo/renderer/GLMatrix.h +++ b/neo/renderer/GLMatrix.h @@ -60,7 +60,7 @@ void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane& in, idPla void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane& in, idPlane& out ); void R_SetupViewMatrix( viewDef_t* viewDef ); -void R_SetupProjectionMatrix( viewDef_t* viewDef ); +void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter ); // RB begin void R_SetupUnprojection( viewDef_t* viewDef ); diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 1931354b..756d3a15 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -5529,26 +5529,43 @@ void idRenderBackend::DrawMotionVectors() // derive the matrix to go from current pixels to previous frame pixels idRenderMatrix inverseMVP; - idRenderMatrix::Inverse( viewDef->worldSpace.mvp, inverseMVP ); + idRenderMatrix::Inverse( viewDef->worldSpace.unjitteredMVP, inverseMVP ); idRenderMatrix motionMatrix; idRenderMatrix::Multiply( prevMVP[mvpIndex], inverseMVP, motionMatrix ); - prevMVP[mvpIndex] = viewDef->worldSpace.mvp; + prevMVP[mvpIndex] = viewDef->worldSpace.unjitteredMVP; - RB_SetMVP( motionMatrix ); + // make sure rpWindowCoord is set even without post processing surfaces in the view + int x = viewDef->viewport.x1; + int y = viewDef->viewport.y1; + int w = viewDef->viewport.x2 - viewDef->viewport.x1 + 1; + int h = viewDef->viewport.y2 - viewDef->viewport.y1 + 1; - GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_DEPTHMASK | GLS_CULL_TWOSIDED ); + // window coord to 0.0 to 1.0 conversion + float windowCoordParm[4]; + windowCoordParm[0] = 1.0f / w; + windowCoordParm[1] = 1.0f / h; + windowCoordParm[2] = w; + windowCoordParm[3] = h; + SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord - renderProgManager.BindShader_MotionVectors(); + if( r_taaMotionVectors.GetBool() && prevViewsValid ) + { + RB_SetMVP( motionMatrix ); - GL_SelectTexture( 0 ); - globalImages->currentRenderHDRImage->Bind(); + GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_DEPTHMASK | GLS_CULL_TWOSIDED ); - GL_SelectTexture( 1 ); - globalImages->currentDepthImage->Bind(); + renderProgManager.BindShader_MotionVectors(); - DrawElementsWithCounters( &unitSquareSurface ); + GL_SelectTexture( 0 ); + globalImages->currentRenderHDRImage->Bind(); + + GL_SelectTexture( 1 ); + globalImages->currentDepthImage->Bind(); + + DrawElementsWithCounters( &unitSquareSurface ); + } renderLog.CloseBlock(); } diff --git a/neo/renderer/RenderCommon.h b/neo/renderer/RenderCommon.h index 8f408741..4859e5de 100644 --- a/neo/renderer/RenderCommon.h +++ b/neo/renderer/RenderCommon.h @@ -472,6 +472,7 @@ struct viewEntity_t float modelViewMatrix[16]; // local coords to eye coords idRenderMatrix mvp; + idRenderMatrix unjitteredMVP; // no TAA subpixel jittering // parallelAddModels will build a chain of surfaces here that will need to // be linked to the lights or added to the drawsurf list in a serial code section @@ -607,6 +608,9 @@ struct viewDef_t idRenderMatrix projectionRenderMatrix; // tech5 version of projectionMatrix // RB begin + float unjitteredProjectionMatrix[16]; // second version without TAA subpixel jittering + idRenderMatrix unjitteredProjectionRenderMatrix; + float unprojectionToCameraMatrix[16]; idRenderMatrix unprojectionToCameraRenderMatrix; @@ -1292,6 +1296,7 @@ extern idCVar r_taaEnableHistoryClamping; extern idCVar r_taaClampingFactor; extern idCVar r_taaNewFrameWeight; extern idCVar r_taaMaxRadiance; +extern idCVar r_taaMotionVectors; // RB end /* diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index 5ea73146..bbf4a273 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -334,11 +334,12 @@ idCVar r_useLightGrid( "r_useLightGrid", "1", CVAR_RENDERER | CVAR_BOOL, "" ); idCVar r_exposure( "r_exposure", "0.5", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_FLOAT, "HDR exposure or LDR brightness [-4.0 .. 4.0]", -4.0f, 4.0f ); idCVar r_useTemporalAA( "r_useTemporalAA", "1", CVAR_RENDERER | CVAR_BOOL, "only disable for debugging" ); -idCVar r_taaJitter( "r_taaJitter", "2", CVAR_RENDERER | CVAR_INTEGER, "0: None, 1: MSAA, 2: Halton, 3: R2 Sequence, 4: White Noise" ); +idCVar r_taaJitter( "r_taaJitter", "3", CVAR_RENDERER | CVAR_INTEGER, "0: None, 1: MSAA, 2: Halton, 3: R2 Sequence, 4: White Noise" ); idCVar r_taaEnableHistoryClamping( "r_taaEnableHistoryClamping", "1", CVAR_RENDERER | CVAR_BOOL, "" ); idCVar r_taaClampingFactor( "r_taaClampingFactor", "1.0", CVAR_RENDERER | CVAR_FLOAT, "" ); idCVar r_taaNewFrameWeight( "r_taaNewFrameWeight", "0.1", CVAR_RENDERER | CVAR_FLOAT, "" ); idCVar r_taaMaxRadiance( "r_taaMaxRadiance", "10000", CVAR_RENDERER | CVAR_FLOAT, "" ); +idCVar r_taaMotionVectors( "r_taaMotionVectors", "1", CVAR_RENDERER | CVAR_BOOL, "" ); // RB end const char* fileExten[4] = { "tga", "png", "jpg", "exr" }; diff --git a/neo/renderer/tr_frontend_main.cpp b/neo/renderer/tr_frontend_main.cpp index 921773c6..9c842ac5 100644 --- a/neo/renderer/tr_frontend_main.cpp +++ b/neo/renderer/tr_frontend_main.cpp @@ -606,7 +606,8 @@ void R_RenderView( viewDef_t* parms ) // we need to set the projection matrix before doing // portal-to-screen scissor calculations - R_SetupProjectionMatrix( tr.viewDef ); + R_SetupProjectionMatrix( tr.viewDef, true ); + R_SetupProjectionMatrix( tr.viewDef, false ); // RB: we need a unprojection matrix to calculate the vertex position based on the depth image value // for some post process shaders @@ -619,6 +620,9 @@ void R_RenderView( viewDef_t* parms ) idRenderMatrix::Transpose( *( idRenderMatrix* )tr.viewDef->worldSpace.modelViewMatrix, viewRenderMatrix ); idRenderMatrix::Multiply( tr.viewDef->projectionRenderMatrix, viewRenderMatrix, tr.viewDef->worldSpace.mvp ); + idRenderMatrix::Transpose( *( idRenderMatrix* )tr.viewDef->unjitteredProjectionMatrix, tr.viewDef->unjitteredProjectionRenderMatrix ); + idRenderMatrix::Multiply( tr.viewDef->unjitteredProjectionRenderMatrix, viewRenderMatrix, tr.viewDef->worldSpace.unjitteredMVP ); + // the planes of the view frustum are needed for portal visibility culling idRenderMatrix::GetFrustumPlanes( tr.viewDef->frustums[FRUSTUM_PRIMARY], tr.viewDef->worldSpace.mvp, false, true );