Improved TAA jittering

This commit is contained in:
Robert Beckebans 2022-04-20 10:54:25 +02:00
parent a7623165b5
commit 39227f1559
6 changed files with 67 additions and 38 deletions

View file

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

View file

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

View file

@ -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();
}

View file

@ -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
/*

View file

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

View file

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