From ea78cf42e3e36b3ebb99073cb07a107ca23607bd Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Wed, 31 Jul 2024 17:04:42 +0200 Subject: [PATCH] Store world normals in gbuffer --- neo/framework/Console.cpp | 23 +++- neo/renderer/Passes/SsaoPass.cpp | 6 +- neo/renderer/RenderBackend.cpp | 83 ++++++++++- .../builtin/SSAO/AmbientOcclusion_AO.ps.hlsl | 10 +- neo/shaders/builtin/SSAO/ssao_compute.cs.hlsl | 4 +- neo/shaders/builtin/post/retro_c64.ps.hlsl | 16 ++- neo/shaders/builtin/post/retro_cpc.ps.hlsl | 130 +++++++++++------- 7 files changed, 203 insertions(+), 69 deletions(-) diff --git a/neo/framework/Console.cpp b/neo/framework/Console.cpp index 1a07b50f..fcaec139 100644 --- a/neo/framework/Console.cpp +++ b/neo/framework/Console.cpp @@ -443,13 +443,30 @@ float idConsoleLocal::DrawFPS( float y ) aaMode = aaValues[ r_antiAliasing.GetInteger() ]; } - idStr resolutionText; - resolutionScale.GetConsoleText( resolutionText ); + static const int rrNumValues = 8; + static const char* rrValues[rrNumValues] = + { + "None", + "C64", + "C64 Hi", + "CPC", + "CPC Hi", + "Sega", + "Sega Hi", + "Sony PSX", + }; + + compile_time_assert( rrNumValues == ( RENDERMODE_PSX + 1 ) ); + + const char* retroRenderMode = rrValues[ r_renderMode.GetInteger() ]; + + //idStr resolutionText; + //resolutionScale.GetConsoleText( resolutionText ); int width = renderSystem->GetWidth(); int height = renderSystem->GetHeight(); - ImGui::TextColored( colorCyan, "API: %s, AA[%i, %i]: %s, %s", API, width, height, aaMode, resolutionText.c_str() ); + ImGui::TextColored( colorCyan, "API: %s, AA[%i, %i]: %s, R: %s", API, width, height, aaMode, retroRenderMode ); ImGui::TextColored( colorGold, "Device: %s", deviceManager->GetRendererString() ); ImGui::TextColored( colorPastelMagenta, "VRAM Usage: %llu MB", commonLocal.GetRendererGpuMemoryMB() ); diff --git a/neo/renderer/Passes/SsaoPass.cpp b/neo/renderer/Passes/SsaoPass.cpp index 187b7f32..13ca8e17 100644 --- a/neo/renderer/Passes/SsaoPass.cpp +++ b/neo/renderer/Passes/SsaoPass.cpp @@ -271,7 +271,11 @@ void SsaoPass::Render( // 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 ); + + // TODO would be nicer and faster to have idRenderMatrix::Copy + idRenderMatrix tmp; + idRenderMatrix::Transpose( *( idRenderMatrix* ) viewDef->worldSpace.modelViewMatrix, tmp ); + idRenderMatrix::Transpose( tmp, ssaoConstants.matWorldToView ); ssaoConstants.clipToView = idVec2( viewDef->projectionMatrix[2 * 4 + 3] / viewDef->projectionMatrix[0 * 4 + 0], diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 70155f37..c5268fcc 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -5116,6 +5116,11 @@ void idRenderBackend::DrawScreenSpaceAmbientOcclusion( const viewDef_t* _viewDef SetVertexParms( RENDERPARM_MODELMATRIX_X, viewDef->unprojectionToCameraRenderMatrix[0], 4 ); + // RB: we need to rotate the normals of the gbuffer from world space to view space + idRenderMatrix viewMatrix; + idRenderMatrix::Transpose( *( idRenderMatrix* ) viewDef->worldSpace.modelViewMatrix, viewMatrix ); + SetVertexParms( RENDERPARM_MODELVIEWMATRIX_X, viewMatrix[0], 4 ); + const float jitterSampleScale = 1.0f; float jitterTexScale[4]; @@ -6251,11 +6256,79 @@ void idRenderBackend::PostProcess( const void* data ) blitParms.targetViewport = nvrhi::Viewport( renderSystem->GetWidth(), renderSystem->GetHeight() ); commonPasses.BlitTexture( commandList, blitParms, &bindingCache ); + globalFramebuffers.smaaBlendFBO->Bind(); + + //GL_Viewport( 0, 0, screenWidth, screenHeight ); + //GL_Scissor( 0, 0, screenWidth, screenHeight ); + + if( r_renderMode.GetInteger() == RENDERMODE_CPC || r_renderMode.GetInteger() == RENDERMODE_CPC_HIGHRES ) + { + // clear the alpha buffer and draw only the hands + weapon into it so + // we can avoid blurring them + renderLog.OpenBlock( "Render_HandsAlpha" ); + + GL_State( GLS_COLORMASK | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS | GLS_CULL_TWOSIDED ); + GL_Color( 0, 0, 0, 1 ); + + renderProgManager.BindShader_Color(); + + currentSpace = NULL; + + // draw shader over entire screen + RB_SetMVP( renderMatrix_identity ); + + DrawElementsWithCounters( &unitSquareSurface ); + + // draw the hands + weapon with alpha 0 + GL_Color( 0, 0, 0, 0 ); + + 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 ); + } + + renderLog.CloseBlock(); + } + + GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_DEPTHMASK | GLS_DEPTHFUNC_ALWAYS | GLS_CULL_TWOSIDED ); + GL_SelectTexture( 0 ); globalImages->smaaBlendImage->Bind(); - globalFramebuffers.ldrFBO->Bind(); - GL_SelectTexture( 1 ); globalImages->blueNoiseImage256->Bind(); @@ -6265,11 +6338,11 @@ void idRenderBackend::PostProcess( const void* data ) GL_SelectTexture( 3 ); if( r_useHierarchicalDepthBuffer.GetBool() ) { - commandList->clearTextureFloat( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) ); - // build hierarchical depth buffer renderLog.OpenBlock( "Render_HiZ" ); + commandList->clearTextureFloat( globalImages->hierarchicalZbufferImage->GetTextureHandle(), nvrhi::AllSubresources, nvrhi::Color( 1.f ) ); + commonPasses.BlitTexture( commandList, globalFramebuffers.csDepthFBO[0]->GetApiObject(), @@ -6287,6 +6360,8 @@ void idRenderBackend::PostProcess( const void* data ) globalImages->currentDepthImage->Bind(); } + globalFramebuffers.ldrFBO->Bind(); + float jitterTexScale[4] = {}; if( r_renderMode.GetInteger() == RENDERMODE_C64 || r_renderMode.GetInteger() == RENDERMODE_C64_HIGHRES ) diff --git a/neo/shaders/builtin/SSAO/AmbientOcclusion_AO.ps.hlsl b/neo/shaders/builtin/SSAO/AmbientOcclusion_AO.ps.hlsl index f3c8e3d9..db7cb523 100644 --- a/neo/shaders/builtin/SSAO/AmbientOcclusion_AO.ps.hlsl +++ b/neo/shaders/builtin/SSAO/AmbientOcclusion_AO.ps.hlsl @@ -361,7 +361,15 @@ void main( PS_IN fragment, out PS_OUT result ) visibility = 0.0; #if 1 - float3 n_C = sampleNormal( t_NormalRoughness, ssP, 0 ); + float3 n_W = sampleNormal( t_NormalRoughness, ssP, 0 ); + + // rotate n_W from world space into view space + float3 n_C; + n_C.x = dot3( rpModelViewMatrixX, n_W ); + n_C.y = dot3( rpModelViewMatrixY, n_W ); + n_C.z = dot3( rpModelViewMatrixZ, n_W ); + + n_C = normalize( n_C ); if( length( n_C ) < 0.01 ) { diff --git a/neo/shaders/builtin/SSAO/ssao_compute.cs.hlsl b/neo/shaders/builtin/SSAO/ssao_compute.cs.hlsl index 445c5546..817c4ad0 100644 --- a/neo/shaders/builtin/SSAO/ssao_compute.cs.hlsl +++ b/neo/shaders/builtin/SSAO/ssao_compute.cs.hlsl @@ -221,9 +221,9 @@ void main( uint3 globalId : SV_DispatchThreadID ) float3 pixelNormal = t_Normals[pixelPos].xyz; #endif - // RB: pixelNormal is already in view space but it has to be negated to look correct which is weird + // RB: pixelNormal has to be negated to look correct which is weird pixelNormal = -normalize( pixelNormal * 2.0 - 1.0 ); - //pixelNormal = normalize( mul( float4( pixelNormal, 0 ), g_Ssao.matWorldToView ).xyz ); + pixelNormal = normalize( mul( float4( pixelNormal, 0 ), g_Ssao.matWorldToView ).xyz ); float2 pixelClipPos = WindowToClip( pixelPos ); float3 pixelViewPos = ViewDepthToViewPos( pixelClipPos.xy, pixelViewDepth ); diff --git a/neo/shaders/builtin/post/retro_c64.ps.hlsl b/neo/shaders/builtin/post/retro_c64.ps.hlsl index ed52c40f..1d9a0a1a 100644 --- a/neo/shaders/builtin/post/retro_c64.ps.hlsl +++ b/neo/shaders/builtin/post/retro_c64.ps.hlsl @@ -34,8 +34,8 @@ If you have questions concerning this license or the applicable additional terms Texture2D t_BaseColor : register( t0 VK_DESCRIPTOR_SET( 0 ) ); Texture2D t_BlueNoise : register( t1 VK_DESCRIPTOR_SET( 0 ) ); -SamplerState samp0 : register(s0 VK_DESCRIPTOR_SET( 1 ) ); -SamplerState samp1 : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256 +SamplerState s_LinearClamp : register(s0 VK_DESCRIPTOR_SET( 1 ) ); +SamplerState s_LinearWrap : register(s1 VK_DESCRIPTOR_SET( 1 ) ); // blue noise 256 struct PS_IN { @@ -226,9 +226,10 @@ void main( PS_IN fragment, out PS_OUT result ) float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR; float3 quantizationPeriod = _float3( 1.0 / NUM_COLORS ); + float3 quantDeviation = Deviation( palette ); // get pixellated base color - float3 color = t_BaseColor.Sample( samp0, uvPixelated * rpWindowCoord.xy ).rgb; + float3 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb; float2 uvDither = uvPixelated; //if( rpJitterTexScale.x > 1.0 ) @@ -259,7 +260,7 @@ void main( PS_IN fragment, out PS_OUT result ) // dithered quantized color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) ); - color.rgb += float3( dither, dither, dither ) * quantizationPeriod; + color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; color = LinearSearch( color, palette ); result.color = float4( color, 1.0 ); @@ -269,11 +270,16 @@ void main( PS_IN fragment, out PS_OUT result ) { color = _float3( uv.x ); color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) ); + color += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; + color = LinearSearch( color.rgb, palette ); + + result.color = float4( color, 1.0 ); + return; } #endif //color.rgb += float3( dither, dither, dither ) * quantizationPeriod; - color.rgb += float3( dither, dither, dither ) * Deviation( palette ) * rpJitterTexScale.y; + color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; // find closest color match from C64 color palette color = LinearSearch( color.rgb, palette ); diff --git a/neo/shaders/builtin/post/retro_cpc.ps.hlsl b/neo/shaders/builtin/post/retro_cpc.ps.hlsl index e5533a04..b4affaeb 100644 --- a/neo/shaders/builtin/post/retro_cpc.ps.hlsl +++ b/neo/shaders/builtin/post/retro_cpc.ps.hlsl @@ -315,28 +315,6 @@ float3 ditherRGB( float2 fragPos, float3 quantDeviation ) return float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; } -float2 cubeProject( float3 p ) -{ - float2 x = p.zy; - float2 y = p.xz; - float2 z = p.xy; - - //select face - p = abs( p ); - if( p.x > p.y && p.x > p.z ) - { - return x; - } - else if( p.y > p.x && p.y > p.z ) - { - return y; - } - else - { - return z; - } -} - void main( PS_IN fragment, out PS_OUT result ) { #if 0 @@ -646,6 +624,18 @@ void main( PS_IN fragment, out PS_OUT result ) RGB( 154, 158, 63 ), }; +#elif 0 + + // Hollow + // https://lospec.com/palette-list/hollow + const float3 palette[NUM_COLORS] = // 4 + { + RGB( 15, 15, 27 ), + RGB( 86, 90, 117 ), + RGB( 198, 183, 190 ), + RGB( 250, 251, 246 ), + }; + #else // https://lospec.com/palette-list/2bit-demichrome @@ -666,7 +656,7 @@ void main( PS_IN fragment, out PS_OUT result ) float3 quantDeviation = Deviation( palette ); // get pixellated base color - float3 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb; + float4 color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ); float2 uvDither = uvPixelated; //if( rpJitterTexScale.x > 1.0 ) @@ -678,40 +668,40 @@ void main( PS_IN fragment, out PS_OUT result ) #if 0 if( uv.y < 0.0625 ) { - color = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) ); + color.rgb = HSVToRGB( float3( uv.x, 1.0, uv.y * 16.0 ) ); - result.color = float4( color, 1.0 ); + result.color = float4( color.rgb, 1.0 ); return; } else if( uv.y < 0.125 ) { // quantized - color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) ); - color = LinearSearch( color, palette ); + color.rgb = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.0625 ) * 16.0 ) ); + color.rgb = LinearSearch( color.rgb, palette ); - result.color = float4( color, 1.0 ); + result.color = float4( color.rgb, 1.0 ); return; } else if( uv.y < 0.1875 ) { // dithered quantized - color = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) ); + color.rgb = HSVToRGB( float3( uv.x, 1.0, ( uv.y - 0.125 ) * 16.0 ) ); color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; - color = LinearSearch( color, palette ); + color.rgb = LinearSearch( color.rgb, palette ); - result.color = float4( color, 1.0 ); + result.color = float4( color.rgb, 1.0 ); return; } else if( uv.y < 0.25 ) { - color = _float3( uv.x ); - color = floor( color * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) ); + color.rgb = _float3( uv.x ); + color.rgb = floor( color.rgb * NUM_COLORS ) * ( 1.0 / ( NUM_COLORS - 1.0 ) ); color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; - color = LinearSearch( color, palette ); + color.rgb = LinearSearch( color.rgb, palette ); - result.color = float4( color, 1.0 ); + result.color = float4( color.rgb, 1.0 ); return; } #endif @@ -720,10 +710,21 @@ void main( PS_IN fragment, out PS_OUT result ) color.rgb += float3( dither, dither, dither ) * quantDeviation * rpJitterTexScale.y; // find closest color match from CPC color palette - color = LinearSearch( color.rgb, palette ); + color.rgb = LinearSearch( color.rgb, palette ); -#if 1 +#if 0 + + // // similar to Obra Dinn + // + + // don't post process the hands, which were drawn with alpha = 0 + if( color.a == 0.0 ) + { + result.color = float4( color.rgb, 1.0 ); + return; + } + // triplanar mapping based on reconstructed depth buffer @@ -765,13 +766,13 @@ void main( PS_IN fragment, out PS_OUT result ) float2 uvY = worldPos.xz; // y facing plane float2 uvZ = worldPos.xy; // z facing plane -#if 0 - uvX = abs( uvX ); - uvY = abs( uvY ); - uvZ = abs( uvZ ); +#if 1 + uvX = abs( uvX );// + 1.0; + uvY = abs( uvY );// + 1.0; + uvZ = abs( uvZ );// + 1.0; #endif -#if 0 +#if 1 uvX *= 4.0; uvY *= 4.0; uvZ *= 4.0; @@ -793,6 +794,24 @@ void main( PS_IN fragment, out PS_OUT result ) float3 triblend = saturate( pow( worldNormal, 4.0 ) ); triblend /= max( dot( triblend, float3( 1, 1, 1 ) ), 0.0001 ); +#if 1 + // change from simple triplanar blending to cubic projection + // which handles diagonal geometry way better + if( ( abs( worldNormal.x ) > abs( worldNormal.y ) ) && ( abs( worldNormal.x ) > abs( worldNormal.z ) ) ) + { + triblend = float3( 1, 0, 0 ); // X axis + } + else if( ( abs( worldNormal.z ) > abs( worldNormal.x ) ) && ( abs( worldNormal.z ) > abs( worldNormal.y ) ) ) + { + triblend = float3( 0, 0, 1 ); // Z axis + + } + else + { + triblend = float3( 0, 1, 0 ); // Y axis + } +#endif + #if 0 // preview blend result.color = float4( triblend.xyz, 1.0 ); @@ -807,29 +826,34 @@ void main( PS_IN fragment, out PS_OUT result ) uvZ.x *= -axisSign.z; #endif - //result.color = float4( suv.xy, 0.0, 1.0 ); - //return; + // FIXME get pixellated base color or not + //float2 pixelatedUVX = floor( uvX / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR; + //float2 pixelatedUVY = floor( uvY / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR; + //float2 pixelatedUVZ = floor( uvZ / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR; - // FIXME get pixellated base color - //color = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb; - color = t_BaseColor.Sample( s_LinearClamp, uv ).rgb; + //float3 pixelatedColor = colX * triblend.x + colY * triblend.y + colZ * triblend.z; + // + //float2 uvPixelated = floor( fragment.position.xy / RESOLUTION_DIVISOR ) * RESOLUTION_DIVISOR; - float3 colX = ditherRGB( uvX, quantDeviation ) * 2.0; - float3 colY = ditherRGB( uvY, quantDeviation ) * 2.0; - float3 colZ = ditherRGB( uvZ, quantDeviation ) * 2.0; + color.rgb = t_BaseColor.Sample( s_LinearClamp, uvPixelated * rpWindowCoord.xy ).rgb; + //color = t_BaseColor.Sample( s_LinearClamp, uv ).rgb; + + float3 colX = ditherRGB( uvX, quantDeviation ) * 1.0; + float3 colY = ditherRGB( uvY, quantDeviation ) * 1.0; + float3 colZ = ditherRGB( uvZ, quantDeviation ) * 1.0; float3 dither3D = colX * triblend.x + colY * triblend.y + colZ * triblend.z; color.rgb += dither3D; // find closest color match from CPC color palette - color = LinearSearch( color.rgb, palette ); + color.rgb = LinearSearch( color.rgb, palette ); #if 0 float2 uvC = cubeProject( abs( worldPos ) ); color.rgb = _float3( DitherArray8x8( uvC ) - 0.5 ); #endif -#if 1 +#if 0 colX = _float3( DitherArray8x8( uvX ) - 0.5 ); colY = _float3( DitherArray8x8( uvY ) - 0.5 ); colZ = _float3( DitherArray8x8( uvZ ) - 0.5 ); @@ -859,5 +883,5 @@ void main( PS_IN fragment, out PS_OUT result ) #endif // cubic mapping //color.rgb = float3( suv.xy * 0.5 + 0.5, 1.0 ); - result.color = float4( color, 1.0 ); + result.color = float4( color.rgb, 1.0 ); }