Donut SSAO is kind of working

This commit is contained in:
Robert Beckebans 2023-02-11 14:24:59 +01:00
parent 9d45866a1a
commit 5de9dd9b68
7 changed files with 49 additions and 43 deletions

View file

@ -535,7 +535,7 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter )
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]
// the transformation into window space has changed from [-1 .. 1] to [0 .. 1]
projectionMatrix[3 * 4 + 2] = -1.0f * zNear;
projectionMatrix[0 * 4 + 3] = 0.0f;
@ -545,7 +545,8 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter )
#else
// alternative Z for better precision in the distance
// alternative far plane at infinity Z for better precision in the distance but still no reversed depth buffer
// see Foundations of Game Engine Development 2, chapter 6.3
float aspect = viewDef->renderView.fov_x / viewDef->renderView.fov_y;
@ -570,7 +571,11 @@ void R_SetupProjectionMatrix( viewDef_t* viewDef, bool doJitter )
projectionMatrix[0 * 4 + 2] = 0.0f;
projectionMatrix[1 * 4 + 2] = 0.0f;
// adjust value to prevent imprecision issues
projectionMatrix[2 * 4 + 2] = -k;
// the clip space Z range has changed from [-1 .. 1] to [0 .. 1] for DX12 & Vulkan
projectionMatrix[3 * 4 + 2] = -k * zNear;
projectionMatrix[0 * 4 + 3] = 0.0f;
@ -665,10 +670,12 @@ create a matrix with similar functionality like gluUnproject, project from windo
*/
void R_SetupUnprojection( viewDef_t* viewDef )
{
// RB: I don't like that this doesn't work
//idRenderMatrix::Inverse( *( idRenderMatrix* ) viewDef->projectionMatrix, viewDef->unprojectionToCameraRenderMatrix );
R_MatrixFullInverse( viewDef->projectionMatrix, viewDef->unprojectionToCameraMatrix );
idRenderMatrix::Transpose( *( idRenderMatrix* )viewDef->unprojectionToCameraMatrix, viewDef->unprojectionToCameraRenderMatrix );
R_MatrixMultiply( viewDef->worldSpace.modelViewMatrix, viewDef->projectionMatrix, viewDef->unprojectionToWorldMatrix );
R_MatrixFullInverse( viewDef->unprojectionToWorldMatrix, viewDef->unprojectionToWorldMatrix );

View file

@ -1,5 +1,8 @@
/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2022 Stephen Pridham (id Tech 4x integration)
* Copyright (C) 2023 Stephen Saunders (id Tech 4x integration)
* Copyright (C) 2023 Robert Beckebans (id Tech 4x integration)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -27,12 +30,12 @@
#include "SsaoPass.h"
static idCVar r_ssaoBackgroundViewDepth( "r_ssaoBackgroundViewDepth", "100", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoRadiusWorld( "r_ssaoRadiusWorld", "0.5", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoSurfaceBias( "r_ssaoSurfaceBias", "0.1", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoBackgroundViewDepth( "r_ssaoBackgroundViewDepth", "100", CVAR_RENDERER | CVAR_FLOAT, "specified in meters" );
static idCVar r_ssaoRadiusWorld( "r_ssaoRadiusWorld", "1.0", CVAR_RENDERER | CVAR_FLOAT, "specified in meters" );
static idCVar r_ssaoSurfaceBias( "r_ssaoSurfaceBias", "0.05", CVAR_RENDERER | CVAR_FLOAT, "specified in meters" );
static idCVar r_ssaoPowerExponent( "r_ssaoPowerExponent", "2", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoBlurSharpness( "r_ssaoBlurSharpness", "16", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoAmount( "r_ssaoAmount", "2", CVAR_RENDERER | CVAR_FLOAT, "" );
static idCVar r_ssaoAmount( "r_ssaoAmount", "4", CVAR_RENDERER | CVAR_FLOAT, "" );
struct SsaoConstants
{
@ -40,8 +43,8 @@ struct SsaoConstants
idVec2 viewportSize;
idRenderMatrix matClipToView;
idRenderMatrix matWorldToView;
idRenderMatrix matViewToWorld;
idRenderMatrix matWorldToView; // unused
idRenderMatrix matViewToWorld; // unused
idVec2 clipToView;
idVec2 invQuantizedGbufferSize;
@ -240,42 +243,44 @@ void SsaoPass::Render(
assert( m_Blur.BindingSets[bindingSetIndex] );
{
nvrhi::Rect viewExtent( viewDef->viewport.x1, viewDef->viewport.x2, viewDef->viewport.y1, viewDef->viewport.y2 );
// RB HACK: add one 1 extra pixel to width and height
nvrhi::Rect viewExtent( viewDef->viewport.x1, viewDef->viewport.x2 + 1, viewDef->viewport.y1, viewDef->viewport.y2 + 1 );
nvrhi::Rect quarterResExtent = viewExtent;
quarterResExtent.minX /= 4;
quarterResExtent.minY /= 4;
quarterResExtent.maxX = ( quarterResExtent.maxX + 3 ) / 4;
quarterResExtent.maxY = ( quarterResExtent.maxY + 3 ) / 4;
// TODO required and remove this by fixing the shaders
renderProgManager.BindShader_TextureVertexColor();
renderProgManager.CommitConstantBuffer( commandList, true );
SsaoConstants ssaoConstants = {};
ssaoConstants.viewportOrigin = idVec2( viewDef->viewport.x1, viewDef->viewport.y1 );
ssaoConstants.viewportSize = idVec2( viewDef->viewport.GetWidth(), viewDef->viewport.GetHeight() );
ssaoConstants.matClipToView = viewDef->unprojectionToCameraRenderMatrix;
// RB: this actually should work but it only works with the old SSAO method ...
//ssaoConstants.matClipToView = viewDef->unprojectionToCameraRenderMatrix;
// SRS - FIXME: These transformations need to be verified
idRenderMatrix::Inverse( *( idRenderMatrix* ) viewDef->projectionMatrix, ssaoConstants.matClipToView );
// RB: TODO: only need for DIRECTIONAL_OCCLUSION
// we don't store the view matrix separatly yet
//ssaoConstants.matViewToWorld = viewDef->worldSpace;
//idRenderMatrix::Inverse( ssaoConstants.matViewToWorld, ssaoConstants.matWorldToView );
// SRS end
float projectionMatrix[16];
//R_MatrixTranspose( viewDef->projectionMatrix, projectionMatrix );
memcpy( projectionMatrix, viewDef->projectionMatrix, 16 * 4 );
ssaoConstants.clipToView = idVec2(
projectionMatrix[2 * 4 + 3] / projectionMatrix[0 * 4 + 0],
projectionMatrix[2 * 4 + 3] / projectionMatrix[1 * 4 + 1] );
ssaoConstants.invQuantizedGbufferSize = 1.f / m_QuantizedGbufferTextureSize;
viewDef->projectionMatrix[2 * 4 + 3] / viewDef->projectionMatrix[0 * 4 + 0],
viewDef->projectionMatrix[2 * 4 + 3] / viewDef->projectionMatrix[1 * 4 + 1] );
ssaoConstants.invQuantizedGbufferSize = idVec2( 1.0f, 1.0f ) / m_QuantizedGbufferTextureSize;
ssaoConstants.quantizedViewportOrigin = idVec2i( quarterResExtent.minX, quarterResExtent.minY ) * 4;
ssaoConstants.amount = r_ssaoAmount.GetFloat();
ssaoConstants.invBackgroundViewDepth = ( r_ssaoBackgroundViewDepth.GetFloat() > 0.f ) ? 1.f / r_ssaoBackgroundViewDepth.GetFloat() : 0.f;
ssaoConstants.radiusWorld = r_ssaoRadiusWorld.GetFloat();
ssaoConstants.surfaceBias = r_ssaoSurfaceBias.GetFloat();
ssaoConstants.powerExponent = r_ssaoPowerExponent.GetFloat();
ssaoConstants.radiusToScreen = 0.5f * viewDef->viewport.GetHeight() * abs( projectionMatrix[1 * 4 + 1] );
ssaoConstants.radiusToScreen = 0.5f * viewDef->viewport.GetHeight() * abs( viewDef->projectionMatrix[1 * 4 + 1] );
commandList->writeBuffer( m_ConstantBuffer, &ssaoConstants, sizeof( ssaoConstants ) );
uint32_t dispatchWidth = ( quarterResExtent.width() + 7 ) / 8;

View file

@ -44,7 +44,7 @@ If you have questions concerning this license or the applicable additional terms
#include <sys/DeviceManager.h>
#include <nvrhi/utils.h>
idCVar r_useNewSsaoPass( "r_useNewSSAOPass", "0", CVAR_RENDERER | CVAR_BOOL, "use the new ssao pass from donut" );
idCVar r_useNewSsaoPass( "r_useNewSSAOPass", "1", CVAR_RENDERER | CVAR_BOOL, "use the new SSAO pass from Donut" );
extern DeviceManager* deviceManager;
#endif

View file

@ -163,8 +163,8 @@ float3 reconstructNonUnitCSFaceNormal( float3 C )
float3 reconstructCSPosition( float2 S, float z )
{
float4 P;
P.z = z * 2.0 - 1.0;
P.xy = ( S * rpWindowCoord.xy ) * 2.0 - 1.0;
P.z = z;// * 2.0 - 1.0;
P.xy = ( S * rpWindowCoord.xy );// * 2.0 - 1.0;
P.w = 1.0;
float4 csP;

View file

@ -176,13 +176,14 @@ float ComputeAO( float3 V, float3 N, float InvR2 )
float2 WindowToClip( float2 windowPos )
{
float2 clipToWindowScale = float2( 0.5f * g_Ssao.viewportSize.x, -0.5f * g_Ssao.viewportSize.y );
float2 clipToWindowBias = g_Ssao.viewportOrigin.xy + g_Ssao.viewportSize.xy * 0.5f;
float2 clipToWindowScale = float2( 0.5 * g_Ssao.viewportSize.x, -0.5 * g_Ssao.viewportSize.y );
float2 clipToWindowBias = g_Ssao.viewportOrigin.xy + g_Ssao.viewportSize.xy * 0.5;
float2 windowToClipScale = 1.f / clipToWindowScale;
float2 windowToClipScale = 1.0 / clipToWindowScale;
float2 windowToClipBias = -clipToWindowBias * windowToClipScale;
// TODO add pixelOffset for TAA
//windowPos = windowPos * 2.0 - 1.0;
return windowPos.xy * windowToClipScale + windowToClipBias;
}
@ -207,7 +208,9 @@ void main( uint3 globalId : SV_DispatchThreadID )
float3 pixelNormal = t_Normals[pixelPos].xyz;
#endif
// RB: pixelNormal is already in view space
// RB: pixelNormal is already in view space but it has to be negated to look correct which is weird
pixelNormal = -normalize( pixelNormal );
//pixelNormal = normalize( float3( pixelNormal.x, 1.0 - pixelNormal.y, -pixelNormal.z ) );
//pixelNormal = normalize( mul( float4( pixelNormal, 0 ), g_Ssao.matWorldToView ).xyz );
float2 pixelClipPos = WindowToClip( pixelPos );

View file

@ -74,22 +74,12 @@ void main( uint3 globalId : SV_DispatchThreadID )
#if LINEAR_DEPTH
float linearDepth = depth;
#else
//float4 clipPos = float4( 0, 0, depth, 1 );
//float4 clipPos = float4( 0, 0, depth * 2.0 - 1.0, 1 );
// adjust depth
depth = ( depth * 2.0 - 1.0 );
float4 clipPos = float4( 0, 0, depth, 1 );
float4 viewPos = mul( clipPos, g_Ssao.matClipToView );
float linearDepth = viewPos.z / viewPos.w;
// HACK: adjust linear depth to fit into [0 .. 16000] range
//linearDepth += 0.35;
//linearDepth = saturate( linearDepth );
//linearDepth = 1.0 - linearDepth; // reverse depth
//linearDepth *= 4000; // zFar
//linearDepth *= DOOM_TO_METERS;
linearDepth *= -1.0f; // now we have something similar to Doom units = inches
linearDepth *= DOOM_TO_METERS;
#endif
depths[y * 4 + x] = linearDepth;

View file

@ -66,7 +66,9 @@ void main( PS_IN fragment, out PS_OUT result )
localNormal.z = sqrt( 1.0f - dot3( localNormal, localNormal ) );
float3 globalNormal;
#if 0
#if 1
// rotate normal into view space
globalNormal.x = dot3( localNormal, fragment.texcoord2 );
globalNormal.y = dot3( localNormal, fragment.texcoord3 );
globalNormal.z = dot3( localNormal, fragment.texcoord4 );
@ -81,6 +83,5 @@ void main( PS_IN fragment, out PS_OUT result )
// RB: rpColor is white and only used to generate the _fa_ uniform array
result.color.rgb = ( globalNormal.xyz * 0.5 + 0.5 ) * fragment.color.rgb;// * rpColor;
//result.color.rgb = ( globalNormal.xyz );// * fragment.color.rgb;// * rpColor;
result.color.a = 1.0;
}