Changed the motionBlur shader to draw motion vectors

This commit is contained in:
Robert Beckebans 2022-04-13 12:35:00 +02:00
parent 2e363d6f99
commit d078ada2d8
12 changed files with 251 additions and 34 deletions

View file

@ -1042,7 +1042,7 @@ void idImageManager::CreateIntrinsicImages()
currentRenderHDRImage64 = globalImages->ImageFromFunction( "_currentRenderHDR64", R_HDR_RGBA16FImage_Res64 );
currentRenderLDR = globalImages->ImageFromFunction( "_currentRenderLDR", R_LdrNativeImage );
taaMotionVectorsImage = ImageFromFunction( "_motionVectors", R_HDR_RGBA16FImage_ResNative ); // RB: could be shared with _currentNormals.zw
taaMotionVectorsImage = ImageFromFunction( "_taaMotionVectors", R_HDR_RGBA16FImage_ResNative ); // RB: could be shared with _currentNormals.zw
taaResolvedImage = ImageFromFunction( "_taaResolved", R_HDR_RGBA16FImage_ResNative_UAV );
taaFeedback1Image = ImageFromFunction( "_taaFeedback1", R_HDR_RGBA16SImage_ResNative_UAV );
taaFeedback2Image = ImageFromFunction( "_taaFeedback2", R_HDR_RGBA16SImage_ResNative_UAV );

View file

@ -678,6 +678,36 @@ void idRenderBackend::GetCurrentBindingLayout( int type )
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearWrapSampler;
}
}
else if( type == BINDING_LAYOUT_TAA_MOTION_VECTORS )
{
if( desc[0].bindings.empty() )
{
desc[0].bindings =
{
nvrhi::BindingSetItem::ConstantBuffer( 0, renderProgManager.ConstantBuffer() ),
nvrhi::BindingSetItem::Texture_SRV( 0, ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID() ),
nvrhi::BindingSetItem::Texture_SRV( 1, ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID() )
};
}
else
{
desc[0].bindings[0].resourceHandle = renderProgManager.ConstantBuffer();
desc[0].bindings[1].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 0 )->GetTextureID();
desc[0].bindings[2].resourceHandle = ( nvrhi::ITexture* )GetImageAt( 1 )->GetTextureID();
}
if( desc[1].bindings.empty() )
{
desc[1].bindings =
{
nvrhi::BindingSetItem::Sampler( 0, commonPasses.m_LinearClampSampler )
};
}
else
{
desc[1].bindings[0].resourceHandle = commonPasses.m_LinearClampSampler;
}
}
else
{
common->FatalError( "Invalid binding set %d\n", renderProgManager.BindingLayoutType() );

View file

@ -146,9 +146,7 @@ void TemporalAntiAliasingPass::Init(
}
m_MotionVectorsBindingSet = device->createBindingSet( bindingSetDesc, m_MotionVectorsBindingLayout );
//m_MotionVectorsFramebufferFactory = std::make_unique<FramebufferFactory>( device );
//m_MotionVectorsFramebufferFactory->RenderTargets = { params.motionVectors };
#if 0
nvrhi::GraphicsPipelineDesc pipelineDesc;
pipelineDesc.primType = nvrhi::PrimitiveType::TriangleStrip;
pipelineDesc.VS = taaMotionVectorsShaderInfo.vs; //m_CommonPasses->m_FullscreenVS;
@ -162,6 +160,7 @@ void TemporalAntiAliasingPass::Init(
//nvrhi::IFramebuffer* sampleFramebuffer = m_MotionVectorsFramebufferFactory->GetFramebuffer( *sampleView );
nvrhi::IFramebuffer* sampleFramebuffer = globalFramebuffers.taaMotionVectorsFBO->GetApiObject();
m_MotionVectorsPso = device->createGraphicsPipeline( pipelineDesc, sampleFramebuffer );
#endif
}
{

View file

@ -5437,10 +5437,20 @@ void idRenderBackend::CalculateAutomaticExposure()
//GL_CheckErrors();
}
void idRenderBackend::TemporalAAPass( const viewDef_t* _viewDef )
void idRenderBackend::DrawMotionVectors()
{
// if we are just doing 2D rendering, no need for HDR TAA
if( viewDef->viewEntitys == NULL )
if( !viewDef->viewEntitys )
{
// 3D views only
return;
}
if( !r_useTemporalAA.GetBool() && r_motionBlur.GetInteger() <= 0 )
{
return;
}
if( viewDef->isSubview )
{
return;
}
@ -5450,7 +5460,129 @@ void idRenderBackend::TemporalAAPass( const viewDef_t* _viewDef )
return;
}
renderLog.OpenBlock( "TemporalAA" );
renderLog.OpenBlock( "Render_MotionVectors" );
// clear the alpha buffer and draw only the hands + weapon into it so
// we can avoid blurring them
GL_State( GLS_COLORMASK | GLS_DEPTHMASK );
GL_Color( 0, 0, 0, 0 );
GL_SelectTexture( 0 );
globalImages->blackImage->Bind();
currentSpace = NULL;
#if 0
TODO mask out the view weapon + hands using the stencil buffer
commandList->clearTextureFloat( globalImages->currentHDRImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 0.f ) );
drawSurf_t** drawSurfs = ( drawSurf_t** )&viewDef->drawSurfs[0];
for( int surfNum = 0; surfNum < viewDef->numDrawSurfs; surfNum++ )
{
const drawSurf_t* surf = drawSurfs[ surfNum ];
if( !surf->space->weaponDepthHack && !surf->space->skipMotionBlur && !surf->material->HasSubview() )
{
// Apply motion blur to this object
continue;
}
const idMaterial* shader = surf->material;
if( shader->Coverage() == MC_TRANSLUCENT )
{
// muzzle flash, etc
continue;
}
// set mvp matrix
if( surf->space != currentSpace )
{
RB_SetMVP( surf->space->mvp );
currentSpace = surf->space;
}
// this could just be a color, but we don't have a skinned color-only prog
if( surf->jointCache )
{
renderProgManager.BindShader_TextureVertexColorSkinned();
}
else
{
renderProgManager.BindShader_TextureVertexColor();
}
// draw it solid
DrawElementsWithCounters( surf );
}
#endif
globalFramebuffers.taaMotionVectorsFBO->Bind();
commandList->clearTextureFloat( globalImages->taaMotionVectorsImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 0.f ) );
// copy off the color buffer and the depth buffer for the motion blur prog
// we use the viewport dimensions for copying the buffers in case resolution scaling is enabled.
//const idScreenRect& viewport = viewDef->viewport;
//globalImages->currentRenderImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
// in stereo rendering, each eye needs to get a separate previous frame mvp
int mvpIndex = ( viewDef->renderView.viewEyeBuffer == 1 ) ? 1 : 0;
// derive the matrix to go from current pixels to previous frame pixels
idRenderMatrix inverseMVP;
idRenderMatrix::Inverse( viewDef->worldSpace.mvp, inverseMVP );
idRenderMatrix motionMatrix;
idRenderMatrix::Multiply( prevMVP[mvpIndex], inverseMVP, motionMatrix );
prevMVP[mvpIndex] = viewDef->worldSpace.mvp;
RB_SetMVP( motionMatrix );
GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_DEPTHMASK | GLS_CULL_TWOSIDED );
renderProgManager.BindShader_MotionVectors();
// let the fragment program know how many samples we are going to use
idVec4 samples( ( float )( 1 << 4 ) ); ///r_motionBlur.GetInteger() ) );
SetFragmentParm( RENDERPARM_OVERBRIGHT, samples.ToFloatPtr() );
GL_SelectTexture( 0 );
globalImages->currentRenderHDRImage->Bind();
GL_SelectTexture( 1 );
globalImages->currentDepthImage->Bind();
DrawElementsWithCounters( &unitSquareSurface );
renderLog.CloseBlock();
}
void idRenderBackend::TemporalAAPass( const viewDef_t* _viewDef )
{
// if we are just doing 2D rendering, no need for HDR TAA
if( viewDef->viewEntitys == NULL )
{
return;
}
if( !r_useTemporalAA.GetBool() )
{
return;
}
if( viewDef->isSubview )
{
return;
}
if( viewDef->renderView.rdflags & RDF_NOAMBIENT )
{
return;
}
renderLog.OpenBlock( "Render_TemporalAA" );
TemporalAntiAliasingParameters params =
{
@ -6787,8 +6919,8 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
float windowCoordParm[4];
windowCoordParm[0] = 1.0f / w;
windowCoordParm[1] = 1.0f / h;
windowCoordParm[2] = 0.0f;
windowCoordParm[3] = 1.0f;
windowCoordParm[2] = w;
windowCoordParm[3] = h;
SetFragmentParm( RENDERPARM_WINDOWCOORD, windowCoordParm ); // rpWindowCoord
// render the remaining surfaces
@ -6802,6 +6934,11 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
//-------------------------------------------------
DBG_RenderDebugTools( drawSurfs, numDrawSurfs );
//-------------------------------------------------
// motion vectors are useful for TAA and motion blur
//-------------------------------------------------
DrawMotionVectors();
//-------------------------------------------------
// resolve of HDR target using temporal anti aliasing before any tonemapping and post processing
//
@ -6885,7 +7022,7 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste
/*
==================
RB_MotionBlur
idRenderBackend::MotionBlur
Experimental feature
==================

View file

@ -341,6 +341,7 @@ private:
void StencilShadowPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight );
void StencilSelectLight( const viewLight_t* vLight );
void DrawMotionVectors();
void TemporalAAPass( const viewDef_t* _viewDef );
// RB: HDR stuff

View file

@ -300,6 +300,14 @@ void idRenderProgManager::Init( nvrhi::IDevice* _device )
bindingLayouts[BINDING_LAYOUT_NORMAL_CUBE] = { device->createBindingLayout( normalCubeBindingLayout ), samplerOneBindingLayout };
auto motionVectorsBindingLayout = nvrhi::BindingLayoutDesc()
.setVisibility( nvrhi::ShaderType::All )
.addItem( nvrhi::BindingLayoutItem::VolatileConstantBuffer( 0 ) )
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 0 ) ) // cube map
.addItem( nvrhi::BindingLayoutItem::Texture_SRV( 1 ) ); // normal map
bindingLayouts[BINDING_LAYOUT_TAA_MOTION_VECTORS] = { device->createBindingLayout( motionVectorsBindingLayout ), samplerOneBindingLayout };
nvrhi::BindingLayoutDesc tonemapLayout;
tonemapLayout.visibility = nvrhi::ShaderType::Pixel;
tonemapLayout.bindings =
@ -463,7 +471,8 @@ void idRenderProgManager::Init( nvrhi::IDevice* _device )
{ BUILTIN_SMAA_BLENDING_WEIGHT_CALCULATION, "builtin/post/SMAA_blending_weight_calc", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_SMAA_NEIGHBORHOOD_BLENDING, "builtin/post/SMAA_final", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_TAA_MOTION_VECTORS, "builtin/post/motion_vectors", "", { { "USE_STENCIL", "0" }, { "QUAD_Z", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_UNKNOWN, BINDING_LAYOUT_TAA_MOTION_VECTORS },
{ BUILTIN_MOTION_BLUR, "builtin/post/motionBlur", "_vectors", { { "VECTORS_ONLY", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_TAA_MOTION_VECTORS },
//{ BUILTIN_TAA_MOTION_VECTORS, "builtin/post/motion_vectors", "", { { "USE_STENCIL", "0" }, { "QUAD_Z", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_UNKNOWN, BINDING_LAYOUT_TAA_MOTION_VECTORS },
{ BUILTIN_TAA_RESOLVE, "builtin/post/taa", "", { { "SAMPLE_COUNT", "1" }, { "USE_CATMULL_ROM_FILTER", "1" } }, false, SHADER_STAGE_COMPUTE, LAYOUT_UNKNOWN, BINDING_LAYOUT_TAA_RESOLVE },
{ BUILTIN_AMBIENT_OCCLUSION, "builtin/SSAO/AmbientOcclusion_AO", "", { { "BRIGHTPASS", "0" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DRAW_AO },
@ -482,7 +491,7 @@ void idRenderProgManager::Init( nvrhi::IDevice* _device )
{ BUILTIN_BINK_SRGB, "builtin/video/bink", "_srgb", { {"USE_SRGB", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_BINK_GUI, "builtin/video/bink_gui", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_STEREO_INTERLACE, "builtin/VR/stereoInterlace", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_MOTION_BLUR, "builtin/post/motionBlur", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
{ BUILTIN_MOTION_BLUR, "builtin/post/motionBlur", "", { { "VECTORS_ONLY", "1" } }, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },
// RB begin
{ BUILTIN_DEBUG_SHADOWMAP, "builtin/debug/debug_shadowmap", "", {}, false, SHADER_STAGE_DEFAULT, LAYOUT_DRAW_VERT, BINDING_LAYOUT_DEFAULT },

View file

@ -968,6 +968,11 @@ public:
BindShader_Builtin( BUILTIN_MOTION_BLUR );
}
void BindShader_MotionVectors()
{
BindShader_Builtin( BUILTIN_TAA_MOTION_VECTORS );
}
void BindShader_DebugShadowMap()
{
BindShader_Builtin( BUILTIN_DEBUG_SHADOWMAP );

View file

@ -336,7 +336,7 @@ 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", "0", 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, "" );

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014 Robert Beckebans
Copyright (C) 2014-2022 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -38,11 +38,14 @@ Texture2D t_ViewDepth : register( t1 VK_DESCRIPTOR_SET( 0 ) );
SamplerState LinearSampler : register( s0 VK_DESCRIPTOR_SET( 1 ) );
struct PS_IN {
struct PS_IN
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT {
struct PS_OUT
{
float4 color : SV_Target0;
};
// *INDENT-ON*
@ -57,37 +60,56 @@ void main( PS_IN fragment, out PS_OUT result )
return;
}
#endif
#if 0 //!VECTORS_ONLY
// don't motion blur the hands, which were drawn with alpha = 0
if( t_ViewColor.Sample( LinearSampler, fragment.texcoord0 ).w == 0.0 )
{
discard;
return;
}
#endif
// derive clip space from the depth buffer and screen position
float windowZ = t_ViewDepth.Sample( LinearSampler, fragment.texcoord0 ).x;
float3 ndc = float3( fragment.texcoord0 * 2.0 - 1.0, windowZ * 2.0 - 1.0 );
float clipW = -rpProjectionMatrixZ.w / ( -rpProjectionMatrixZ.z - ndc.z );
//float3 ndc = float3( fragment.texcoord0 * 2.0 - 1.0, windowZ * 2.0 - 1.0 );
//float clipW = -rpProjectionMatrixZ.w / ( -rpProjectionMatrixZ.z - ndc.z );
float3 ndc = float3( fragment.texcoord0.x * 2.0 - 1.0, 1.0 - fragment.texcoord0.y * 2.0, windowZ );
float clipW = 1;
float4 clip = float4( ndc * clipW, clipW );
// convert from clip space this frame to clip space previous frame
float4 reClip;
reClip.x = dot( rpMVPmatrixX, clip );
reClip.y = dot( rpMVPmatrixY, clip );
reClip.z = dot( rpMVPmatrixZ, clip );
reClip.w = dot( rpMVPmatrixW, clip );
float4 prevClipPos;
prevClipPos.x = dot( rpMVPmatrixX, clip );
prevClipPos.y = dot( rpMVPmatrixY, clip );
prevClipPos.z = dot( rpMVPmatrixZ, clip );
prevClipPos.w = dot( rpMVPmatrixW, clip );
if( prevClipPos.w <= 0 )
{
return;
}
// convert to NDC values
float2 prevTexCoord;
prevTexCoord.x = ( reClip.x / reClip.w ) * 0.5 + 0.5;
prevTexCoord.y = ( reClip.y / reClip.w ) * 0.5 + 0.5;
prevTexCoord.x = 0.5 + ( prevClipPos.x / prevClipPos.w ) * 0.5;
prevTexCoord.y = 0.5 - ( prevClipPos.y / prevClipPos.w ) * 0.5;
// sample along the line from prevTexCoord to fragment.texcoord0
float2 texCoord = prevTexCoord; //fragment.texcoord0;
float2 delta = ( fragment.texcoord0 - prevTexCoord );
#if VECTORS_ONLY
float2 prevWindowPos = prevTexCoord * rpWindowCoord.zw;
float2 deltaPos = prevWindowPos - fragment.position.xy;
float2 deltaUV = prevTexCoord - fragment.texcoord0;
result.color = float4( deltaPos, 0.0, 1.0 );
#else
float3 sum = _float3( 0.0 );
float goodSamples = 0.0;
float samples = rpOverbright.x;
@ -103,4 +125,5 @@ void main( PS_IN fragment, out PS_OUT result )
float invScale = 1.0 / goodSamples;
result.color = float4( sum * invScale, 1.0 );
#endif
}

View file

@ -30,19 +30,23 @@ If you have questions concerning this license or the applicable additional terms
// *INDENT-OFF*
struct VS_IN {
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
};
struct VS_OUT {
float4 position : POSITION;
float2 texcoord0 : TEXCOORD0;
struct VS_OUT
{
float4 position : SV_Position;
float2 texcoord0 : TEXCOORD0_centroid;
};
// *INDENT-ON*
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.position.y = -result.position.y;
result.texcoord0 = vertex.texcoord;
}

View file

@ -149,6 +149,7 @@ void Preload( int2 sharedID, int2 globalID )
{
#if SAMPLE_COUNT == 1
float3 color = PQEncode( t_UnfilteredRT[globalID].rgb );
//float3 color = ( t_UnfilteredRT[globalID].rgb );
float2 motion = t_MotionVectors[globalID].rg;
float motionLength = dot( motion, motion );
#else
@ -309,6 +310,14 @@ void main(
}
float3 result = PQDecode( resultPQ );
//float3 result = resultPQ;
#if 0
// Show motion vectors
result = float3( longestMV, 0.0 );
resultPQ = PQEncode( result );
#endif
u_ColorOutput[outputPixelPosition] = float4( result, 1.0 );
u_FeedbackOutput[outputPixelPosition] = float4( resultPQ, 0.0 );

View file

@ -68,15 +68,15 @@ builtin/post/SMAA_blending_weight_calc.vs.hlsl -T vs_5_0
builtin/post/SMAA_blending_weight_calc.ps.hlsl -T ps_5_0
builtin/post/SMAA_final.vs.hlsl -T vs_5_0
builtin/post/SMAA_final.ps.hlsl -T ps_5_0
builtin/post/motionBlur.vs.hlsl -T vs_5_0
builtin/post/motionBlur.ps.hlsl -T ps_5_0
builtin/post/motionBlur.vs.hlsl -T vs_5_0 -D VECTORS_ONLY={0,1}
builtin/post/motionBlur.ps.hlsl -T ps_5_0 -D VECTORS_ONLY={0,1}
builtin/post/exposure.cs.hlsl -T cs_5_0 -D HISTOGRAM_BINS=256
builtin/post/histogram.cs.hlsl -T cs_5_0 -D HISTOGRAM_BINS=256 -D SOURCE_ARRAY={0,1}
builtin/post/tonemapping.ps.hlsl -T ps_5_0 -D HISTOGRAM_BINS=256 -D SOURCE_ARRAY={0,1} -D QUAD_Z={0,1}
builtin/post/tonemapping.vs.hlsl -T vs_5_0 -D HISTOGRAM_BINS=256 -D SOURCE_ARRAY={0,1} -D QUAD_Z={0,1}
builtin/post/motion_vectors.vs.hlsl -T vs_5_0 -D USE_STENCIL=0 -D QUAD_Z={0,1}
builtin/post/motion_vectors.ps.hlsl -T ps_5_0 -D USE_STENCIL=0 -D QUAD_Z={0,1}
builtin/post/taa.cs.hlsl -T cs_5_0 -D SAMPLE_COUNT={1,2,4} -D USE_CATMULL_ROM_FILTER=1
builtin/post/taa.cs.hlsl -T cs_5_0 -D SAMPLE_COUNT={1,2,4} -D USE_CATMULL_ROM_FILTER={0,1}
builtin/SSAO/AmbientOcclusion_AO.vs.hlsl -T vs_5_0 -D BRIGHTPASS={0,1}
builtin/SSAO/AmbientOcclusion_AO.ps.hlsl -T ps_5_0 -D BRIGHTPASS={0,1}