rt denoiser: rework motion vectors, add simple temporal reprojection

This commit is contained in:
LifeKILLED 2023-01-30 08:53:18 +04:00
parent 3a87934415
commit 164259d6b1
11 changed files with 183 additions and 90 deletions

View File

@ -4,6 +4,10 @@
#include "utils.glsl"
#include "color_spaces.glsl"
#define GLSL
#include "ray_interop.h"
#undef GLSL
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba16f) uniform image2D out_dest;
@ -19,7 +23,9 @@ layout(set = 0, binding = 5, rgba16f) uniform readonly image2D light_point_specu
layout(set = 0, binding = 6, rgba16f) uniform readonly image2D emissive;
layout(set = 0, binding = 7, rgba32f) uniform readonly image2D position_t;
layout(set = 0, binding = 8, rgba32f) uniform readonly image2D prev_position_t;
layout(set = 0, binding = 8, rgba32f) uniform readonly image2D geometry_prev_position;
layout(set = 0, binding = 10) uniform UBO { UniformBuffer ubo; } ubo;
//layout(set = 0, binding = 7, rgba32f) uniform readonly image2D position_t;
//layout(set = 0, binding = 8, rgba16f) uniform readonly image2D normals_gs;
@ -211,6 +217,43 @@ void main() {
// DEBUG motion vectors
//colour = vec3(length(imageLoad(position_t, pix).rgb - imageLoad(prev_position_t, pix).rgb));
imageStore(out_dest, pix, vec4(colour, 0.));
// TODO: need to extract reprojecting from this shader because reprojected stuff need svgf denoising pass after it
const vec3 origin = (ubo.ubo.inv_view * vec4(0., 0., 0., 1.)).xyz;
const float depth = length(origin - imageLoad(position_t, pix).xyz);
const vec3 prev_position = imageLoad(geometry_prev_position, pix).rgb;
const vec4 clip_space = inverse(ubo.ubo.prev_inv_proj) * vec4((inverse(ubo.ubo.prev_inv_view) * vec4(prev_position, 1.)).xyz, 1.);
const vec2 reproj_uv = clip_space.xy / clip_space.w;
const ivec2 reproj_pix = ivec2((reproj_uv * 0.5 + vec2(0.5)) * vec2(res));
const vec3 prev_origin = (ubo.ubo.prev_inv_view * vec4(0., 0., 0., 1.)).xyz;
const float depth_nessesary = length(prev_position - prev_origin);
const float depth_treshold = 0.01 * clip_space.w;
float better_depth_offset = depth_treshold;
vec3 history_colour = colour;
for(int x = -1; x <=1; x++) {
for(int y = -1; y <=1; y++) {
const ivec2 p = reproj_pix + ivec2(x, y);
if (any(greaterThanEqual(p, res)) || any(lessThan(p, ivec2(0)))) {
continue;
}
const vec4 history_colour_depth = imageLoad( prev_dest, reproj_pix );
const float history_depth = history_colour_depth.w;
const float depth_offset = abs(history_depth - depth_nessesary);
if ( depth_offset < better_depth_offset ) {
better_depth_offset = depth_offset;
history_colour = history_colour_depth.rgb;
}
}
}
if (better_depth_offset < depth_treshold) {
colour = mix(colour, history_colour, 0.8);
}
// DEBUG motion vectors
//colour = vec3(length(imageLoad(position_t, pix).rgb - imageLoad(geometry_prev_position, pix).rgb));
//const vec4 prev_colour = imageLoad(prev_dest, pix);
//colour = mix(colour, prev_colour.rgb, vec3(.9));
imageStore(out_dest, pix, vec4(colour, depth));
//imageStore(out_dest, pix, imageLoad(light_poly, pix));
}

View File

@ -18,7 +18,7 @@
X(12, normals_gs, rgba16f) \
X(13, material_rmxx, rgba8) \
X(14, emissive, rgba16f) \
X(15, prev_position_t, rgba32f) \
X(15, geometry_prev_position, rgba32f) \
#define RAY_LIGHT_DIRECT_INPUTS(X) \
X(10, position_t, rgba32f) \

View File

@ -55,5 +55,5 @@ void main() {
imageStore(out_normals_gs, pix, payload.normals_gs);
imageStore(out_material_rmxx, pix, payload.material_rmxx);
imageStore(out_emissive, pix, payload.emissive);
imageStore(out_prev_position_t, pix, payload.prev_pos_t);
imageStore(out_geometry_prev_position, pix, payload.prev_pos_t);
}

View File

@ -41,5 +41,5 @@ void main() {
imageStore(out_normals_gs, ivec2(gl_LaunchIDEXT.xy), payload.normals_gs);
imageStore(out_material_rmxx, ivec2(gl_LaunchIDEXT.xy), payload.material_rmxx);
imageStore(out_emissive, ivec2(gl_LaunchIDEXT.xy), payload.emissive);
imageStore(out_prev_position_t, ivec2(gl_LaunchIDEXT.xy), payload.prev_pos_t);
imageStore(out_geometry_prev_position, ivec2(gl_LaunchIDEXT.xy), payload.prev_pos_t);
}

View File

@ -13,6 +13,7 @@
#include "vk_geometry.h"
#include "vk_light.h"
#include "vk_mapents.h"
#include "vk_previous_frame.h"
#include "ref_params.h"
#include "eiface.h"
@ -33,16 +34,6 @@ static struct {
int rtable[MOD_FRAMES][MOD_FRAMES];
} g_brush;
#define MAX_BRUSH_ENTITIES_PREV_STATES 1024
typedef struct {
matrix4x4 prev_model_transform;
float prev_time;
} brush_entity_prev_state_t;
static brush_entity_prev_state_t g_brush_prev_states[MAX_BRUSH_ENTITIES_PREV_STATES];
void VK_InitRandomTable( void )
{
int tu, tv;
@ -101,10 +92,7 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
uint16_t *indices;
r_geometry_buffer_lock_t buffer;
if (ent->index < MAX_BRUSH_ENTITIES_PREV_STATES) {
prev_time = g_brush_prev_states[ent->index].prev_time;
g_brush_prev_states[ent->index].prev_time = time;
} else gEngine.Con_Printf(S_ERROR "Brush entities previous frame states pool is overflow, increase it. Index is %s\n", ent->index );
prev_time = R_PrevFrame_Time(ent->index);
#define MAX_WATER_VERTICES 16
vk_vertex_t poly_vertices[MAX_WATER_VERTICES];
@ -289,17 +277,9 @@ void XVK_DrawWaterSurfaces( const cl_entity_t *ent )
EmitWaterPolys( ent, surf, false );
}
int entity_id = ent->index;
if (entity_id < MAX_BRUSH_ENTITIES_PREV_STATES)
Matrix4x4_Copy( *VK_RenderGetLastFrameTransform(), g_brush_prev_states[entity_id].prev_model_transform );
// submit as dynamic model
VK_RenderModelDynamicCommit();
if (entity_id < MAX_BRUSH_ENTITIES_PREV_STATES)
Matrix4x4_Copy( g_brush_prev_states[entity_id].prev_model_transform, *VK_RenderGetLastFrameTransform() );
// TODO:
// - upload water geometry only once, animate in compute/vertex shader
}
@ -392,18 +372,8 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, const matrix4x4
}
}
int entity_id = ent->index;
if (entity_id < MAX_BRUSH_ENTITIES_PREV_STATES) {
Matrix4x4_Copy( bmodel->render_model.prev_transform,
g_brush_prev_states[entity_id].prev_model_transform );
} else gEngine.Con_Printf(S_ERROR "Brush entities previous frame states pool is overflow, increase it. Index is %s\n", ent->index );
bmodel->render_model.render_mode = render_mode;
VK_RenderModelDraw(ent, &bmodel->render_model);
if (entity_id >= 0 && entity_id < MAX_BRUSH_ENTITIES_PREV_STATES) {
Matrix4x4_Copy( g_brush_prev_states[entity_id].prev_model_transform, bmodel->render_model.prev_transform );
}
}
static qboolean renderableSurface( const msurface_t *surf, int i ) {

104
ref_vk/vk_previous_frame.c Normal file
View File

@ -0,0 +1,104 @@
#include "vk_studio.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "vk_render.h"
#include "vk_geometry.h"
#include "camera.h"
#include "xash3d_mathlib.h"
#include "const.h"
#include "r_studioint.h"
#include "triangleapi.h"
#include "studio.h"
#include "pm_local.h"
#include "cl_tent.h"
#include "pmtrace.h"
#include "protocol.h"
#include "enginefeatures.h"
#include "pm_movevars.h"
#include <memory.h>
#include <stdlib.h>
#define PREV_STATES_COUNT 1024
#define PREV_FRAMES_COUNT 2
typedef struct {
matrix3x4 bones_worldtransform[MAXSTUDIOBONES];
matrix4x4 model_transform;
float time;
int bones_update_frame_index;
} prev_state_t;
typedef struct {
prev_state_t prev_states[PREV_FRAMES_COUNT][PREV_STATES_COUNT];
int frame_index;
int current_frame_id;
int previous_frame_id;
} prev_states_storage_t;
prev_states_storage_t g_prev = { 0 };
inline int clampIndex( int index, int array_length )
{
if (index < 0)
return 0;
else if (index >= array_length)
return array_length - 1;
return index;
}
prev_state_t* prevStateInArrayBounds( int frame_storage_id, int entity_id )
{
int clamped_frame_id = clampIndex( frame_storage_id, PREV_FRAMES_COUNT );
int clamped_entity_id = clampIndex( entity_id, PREV_STATES_COUNT );
return &g_prev.prev_states[clamped_frame_id][clamped_entity_id];
}
#define PREV_FRAME() prevStateInArrayBounds( g_prev.previous_frame_id, entity_id )
#define CURRENT_FRAME() prevStateInArrayBounds( g_prev.current_frame_id, entity_id )
void R_PrevFrame_StartFrame( void )
{
g_prev.frame_index++;
g_prev.current_frame_id = g_prev.frame_index % PREV_FRAMES_COUNT;
g_prev.previous_frame_id = g_prev.frame_index - 1;
}
void R_PrevFrame_SaveCurrentBoneTransforms( int entity_id, matrix3x4* bones_transforms )
{
prev_state_t *state = CURRENT_FRAME();
if (state->bones_update_frame_index == g_prev.frame_index)
return; // already updated for this entity
state->bones_update_frame_index = g_prev.frame_index;
for( int i = 0; i < MAXSTUDIOBONES; i++ )
{
Matrix3x4_Copy(state->bones_worldtransform[i], bones_transforms[i]);
}
}
void R_PrevFrame_SaveCurrentState( int entity_id, matrix4x4 model_transform )
{
prev_state_t* state = CURRENT_FRAME();
Matrix4x4_Copy( state->model_transform, model_transform );
state->time = gpGlobals->time;
}
matrix3x4* R_PrevFrame_BoneTransforms( int entity_id )
{
return PREV_FRAME()->bones_worldtransform;
}
void R_PrevFrame_ModelTransform( int entity_id, matrix4x4 model_matrix )
{
Matrix4x4_Copy(model_matrix, PREV_FRAME()->model_transform);
}
float R_PrevFrame_Time( int entity_id )
{
return PREV_FRAME()->time;
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "vk_common.h"
void R_PrevFrame_StartFrame(void);
void R_PrevFrame_SaveCurrentBoneTransforms(int entity_id, matrix3x4* bones_transforms);
void R_PrevFrame_SaveCurrentState(int entity_id, matrix4x4 model_transform);
matrix3x4* R_PrevFrame_BoneTransforms(int entity_id);
void R_PrevFrame_ModelTransform( int entity_id, matrix4x4 model_matrix );
float R_PrevFrame_Time(int entity_id);

View File

@ -12,6 +12,7 @@
#include "vk_rtx.h"
#include "vk_descriptor.h"
#include "vk_framectl.h" // FIXME needed for dynamic models cmdbuf
#include "vk_previous_frame.h"
#include "alolcator.h"
#include "eiface.h"
@ -682,10 +683,16 @@ void VK_RenderModelDraw( const cl_entity_t *ent, vk_render_model_t* model ) {
int vertex_offset = 0;
if (g_render_state.current_frame_is_ray_traced) {
if (ent != NULL && model != NULL) {
R_PrevFrame_ModelTransform( ent->index, model->prev_transform );
R_PrevFrame_SaveCurrentState( ent->index, g_render_state.model );
}
else {
Matrix4x4_Copy( model->prev_transform, g_render_state.model );
}
VK_RayFrameAddModel(model->ray_model, model, (const matrix3x4*)g_render_state.model, g_render_state.dirty_uniform_data.color, ent ? ent->curstate.rendercolor : (color24){255,255,255});
// store current transform here before it puts to entity history
Matrix4x4_Copy( model->prev_transform, g_render_state.model );
return;
}
@ -751,10 +758,6 @@ static struct {
vk_render_geometry_t geometries[MAX_DYNAMIC_GEOMETRY];
} g_dynamic_model = {0};
matrix4x4 *VK_RenderGetLastFrameTransform( void ) {
return &g_dynamic_model.model.prev_transform;
}
void VK_RenderModelDynamicBegin( int render_mode, const char *debug_name_fmt, ... ) {
va_list argptr;
va_start( argptr, debug_name_fmt );

View File

@ -103,5 +103,3 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf );
void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage img_dst, uint32_t w, uint32_t h );
void VK_Render_FIXME_Barrier( VkCommandBuffer cmdbuf );
matrix4x4* VK_RenderGetLastFrameTransform( void );

View File

@ -15,6 +15,7 @@
#include "vk_ray_internal.h"
#include "vk_staging.h"
#include "vk_textures.h"
#include "vk_previous_frame.h"
#include "alolcator.h"
@ -137,6 +138,8 @@ void VK_RayFrameBegin( void ) {
XVK_RayModel_ClearForNextFrame();
R_PrevFrame_StartFrame();
// TODO: move all lighting update to scene?
if (g_rtx.reload_lighting) {
g_rtx.reload_lighting = false;

View File

@ -3,6 +3,7 @@
#include "vk_textures.h"
#include "vk_render.h"
#include "vk_geometry.h"
#include "vk_previous_frame.h"
#include "camera.h"
#include "xash3d_mathlib.h"
@ -125,9 +126,6 @@ static cvar_t *cl_himodels;
static r_studio_interface_t *pStudioDraw;
static studio_draw_state_t g_studio; // global studio state
#define MAX_ENTITIES_PREV_STATES_STUDIO 1024
static studio_entity_prev_state_t g_entity_prev_states[MAX_ENTITIES_PREV_STATES_STUDIO];
// global variables
static qboolean m_fDoRemap;
mstudiomodel_t *m_pSubModel;
@ -1072,26 +1070,6 @@ static void R_StudioSaveBones( void )
}
}
/*
====================
SaveTransformsForNextFrame
====================
*/
static void R_StudioSaveTransformsForNextFrame( matrix3x4* bones_transforms )
{
if (RI.currententity->index >= MAX_ENTITIES_PREV_STATES_STUDIO)
return;
studio_entity_prev_state_t *prev_state = &g_entity_prev_states[RI.currententity->index];
for( int i = 0; i < m_pStudioHeader->numbones; i++ )
{
Matrix3x4_Copy(prev_state->worldtransform[i], bones_transforms[i]);
}
}
/*
====================
StudioBuildNormalTable
@ -2158,14 +2136,6 @@ static void R_StudioDrawPoints( void )
pskinref = (short *)((byte *)m_pStudioHeader + m_pStudioHeader->skinindex);
if( m_skinnum != 0 ) pskinref += (m_skinnum * m_pStudioHeader->numskinref);
studio_entity_prev_state_t *prev_frame_state = &g_entity_prev_states[RI.currententity->index];
if (RI.currententity->index >= MAX_ENTITIES_PREV_STATES_STUDIO)
{
gEngine.Con_Printf(S_ERROR "Studio entities previous frame states pool is overflow, increase it. Index is %s\n", RI.currententity->index);
prev_frame_state = &g_entity_prev_states[MAX_ENTITIES_PREV_STATES_STUDIO - 1]; // fallback to last element
}
if( FBitSet( m_pStudioHeader->flags, STUDIO_HAS_BONEWEIGHTS ) && m_pSubModel->blendvertinfoindex != 0 && m_pSubModel->blendnorminfoindex != 0 )
{
mstudioboneweight_t *pvertweight = (mstudioboneweight_t *)((byte *)m_pStudioHeader + m_pSubModel->blendvertinfoindex);
@ -2179,9 +2149,10 @@ static void R_StudioDrawPoints( void )
R_LightStrength( pvertbone[i], pstudioverts[i], g_studio.lightpos[i] );
}
matrix3x4* prev_bones_transforms = R_PrevFrame_BoneTransforms( RI.currententity->index );
for( i = 0; i < m_pSubModel->numverts; i++ )
{
R_StudioComputeSkinMatrix( &pvertweight[i], prev_frame_state->worldtransform, skinMat );
R_StudioComputeSkinMatrix( &pvertweight[i], prev_bones_transforms, skinMat );
Matrix3x4_VectorTransform( skinMat, pstudioverts[i], g_studio.prev_verts[i] );
}
@ -2191,18 +2162,19 @@ static void R_StudioDrawPoints( void )
Matrix3x4_VectorRotate( skinMat, pstudionorms[i], g_studio.norms[i] );
}
R_StudioSaveTransformsForNextFrame (g_studio.worldtransform );
R_PrevFrame_SaveCurrentBoneTransforms( RI.currententity->index, g_studio.worldtransform );
}
else
{
matrix3x4* prev_bones_transforms = R_PrevFrame_BoneTransforms( RI.currententity->index );
for( i = 0; i < m_pSubModel->numverts; i++ )
{
Matrix3x4_VectorTransform( g_studio.bonestransform[pvertbone[i]], pstudioverts[i], g_studio.verts[i] );
Matrix3x4_VectorTransform( prev_frame_state->worldtransform[pvertbone[i]], pstudioverts[i], g_studio.prev_verts[i] );
Matrix3x4_VectorTransform( prev_bones_transforms[pvertbone[i]], pstudioverts[i], g_studio.prev_verts[i] );
R_LightStrength( pvertbone[i], pstudioverts[i], g_studio.lightpos[i] );
}
R_StudioSaveTransformsForNextFrame( g_studio.bonestransform );
R_PrevFrame_SaveCurrentBoneTransforms( RI.currententity->index, g_studio.bonestransform );
}
// generate shared normals for properly scaling glowing shell
@ -2328,17 +2300,7 @@ static void R_StudioDrawPoints( void )
*/
}
int entity_id = RI.currententity->index;
if (entity_id < MAX_ENTITIES_PREV_STATES_STUDIO) {
Matrix4x4_Copy( *VK_RenderGetLastFrameTransform(), g_entity_prev_states[entity_id].prev_transform );
} else gEngine.Con_Printf(S_ERROR "Studio entities last states pool is overflow, increase it. Index is %s\n", entity_id );
VK_RenderModelDynamicCommit();
if (entity_id < MAX_ENTITIES_PREV_STATES_STUDIO) {
Matrix4x4_Copy( g_entity_prev_states[entity_id].prev_transform, *VK_RenderGetLastFrameTransform() );
}
}
static void R_StudioSetRemapColors( int newTop, int newBottom )