Added bilateral blur to SSAO

This commit is contained in:
Robert Beckebans 2016-01-02 23:59:44 +01:00
parent e555e83119
commit 9f83e84f6f
11 changed files with 515 additions and 16 deletions

View file

@ -60,7 +60,7 @@ const float METERS_TO_DOOM = ( 1.0 / DOOM_TO_METERS ); // meters to doom
/** Used for preventing AO computation on the sky (at infinite depth) and defining the CS Z to bilateral depth key scaling.
This need not match the real far plane but should not be much more than it.*/
const float FAR_PLANE_Z = -4000.0;// * METERS_TO_DOOM;
const float FAR_PLANE_Z = -4000.0;
/** World-space AO radius in scene units (r). e.g., 1.0m */
const float radius = 1.0 * METERS_TO_DOOM;
@ -71,7 +71,7 @@ const float invRadius2 = 1.0 / radius2;
const float bias = 0.01 * METERS_TO_DOOM;
/** intensity / radius^6 */
const float intensity = 0.2;
const float intensity = 0.5;
const float intensityDivR6 = intensity / ( radius* radius* radius* radius* radius* radius );
const float projScale = 300.0;// * METERS_TO_DOOM;
@ -151,6 +151,16 @@ float3 getPosition( float2 ssP, sampler2D cszBuffer )
csP.xyz /= csP.w;
#if 0
float4 wP;
wP.x = dot4( csP, rpModelMatrixX );
wP.y = dot4( csP, rpModelMatrixY );
wP.z = dot4( csP, rpModelMatrixZ );
wP.w = dot4( csP, rpModelMatrixW );
//wP.xyz /= wP.w;
return wP.xyz;
#endif
return csP.xyz;
}
@ -190,9 +200,18 @@ float3 getOffsetPosition( ivec2 issC, vec2 unitOffset, float ssR, sampler2D cszB
csP.y = dot4( P, rpProjectionMatrixY );
csP.z = dot4( P, rpProjectionMatrixZ );
csP.w = dot4( P, rpProjectionMatrixW );
csP.xyz /= csP.w;
#if 0
float4 wP;
wP.x = dot4( csP, rpModelMatrixX );
wP.y = dot4( csP, rpModelMatrixY );
wP.z = dot4( csP, rpModelMatrixZ );
wP.w = dot4( csP, rpModelMatrixW );
//wP.xyz /= wP.w;
return wP.xyz;
#endif
return csP.xyz;
}
@ -219,7 +238,7 @@ float fallOffFunction( float vv, float vn, float epsilon )
// contribution still falls off with radius^2, but we've adjusted the rate in a way that is
// more computationally efficient and happens to be aesthetically pleasing. Assumes
// division by radius^6 in main()
// return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
//return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
// D: Low contrast, no division operation
//return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
@ -229,12 +248,13 @@ float fallOffFunction( float vv, float vn, float epsilon )
float aoValueFromPositionsAndNormal( float3 C, float3 n_C, float3 Q )
{
float3 v = Q - C;
//v = normalize( v );
float vv = dot( v, v );
float vn = dot( v, n_C );
const float epsilon = 0.001;
// Without the angular adjustment term, surfaces seen head on have less AO
return fallOffFunction( vv, vn, epsilon ) * lerp( 1.0, max( 0.0, 1.5 * n_C.z ), 0.35 );
return fallOffFunction( vv, vn, epsilon );// * lerp( 1.0, max( 0.0, 1.5 * n_C.z ), 0.35 );
}
@ -281,7 +301,7 @@ void main( PS_IN fragment, out PS_OUT result )
result.color = float4( 0.0, 0.0, 0.0, 1.0 );
#if 1
if( fragment.texcoord0.x < 0.5 )
if( fragment.texcoord0.x < 0.15 )
{
discard;
}
@ -300,19 +320,28 @@ void main( PS_IN fragment, out PS_OUT result )
// World space point being shaded
vec3 C = getPosition( ssC, CS_Z_buffer );
//float z = length( C - rpGlobalEyePos.xyz ) * 10.0;
//float z = length( C - rpGlobalEyePos.xyz );
bilateralKey = CSZToKey( C.z );
visibility = 0.0;
#if 1
#if 0
//vec3 n_C = texelFetch( normal_buffer, ivec2( gl_FragCoord.xy ), 0 ).xyz;
//n_C = normalize( n_C * normal_readMultiplyFirst.xyz + normal_readAddSecond.xyz );
float3 n_C = tex2D( samp0, fragment.texcoord0 ).rgb * 2.0 - 1.0;
n_C = normalize( n_C );
//n_C = -n_C;
if( length( n_C ) < 0.1 )
{
visibility = 1.0;
return;
}
#else
// Reconstruct normals from positions.
float3 n_C = reconstructCSFaceNormal( C );
float3 n_C = reconstructNonUnitCSFaceNormal( C );
// Since n_C is computed from the cross product of cmaera-space edge vectors from points at adjacent pixels, its magnitude will be proportional to the square of distance from the camera
if( dot( n_C, n_C ) > ( square( C.z * C.z * 0.00006 ) ) ) // if the threshold # is too big you will see black dots where we used a bad normal at edges, too small -> white
{
@ -320,6 +349,7 @@ void main( PS_IN fragment, out PS_OUT result )
// except at depth discontinuities, where they will be large and lead
// to 1-pixel false occlusions because they are not reliable
visibility = 1.0;
//result.color = float4( visibility, visibility, visibility, 1.0 );
return;
}
else
@ -331,7 +361,7 @@ void main( PS_IN fragment, out PS_OUT result )
// Hash function used in the HPG12 AlchemyAO paper
float randomPatternRotationAngle = ( ( ( 3 * issC.x ) ^ ( issC.y + issC.x * issC.y ) )
#if TEMPORALLY_VARY_SAMPLES
+ g3d_SceneTime
+ rpJitterTexOffset.x
#endif
) * 10;
@ -339,7 +369,7 @@ void main( PS_IN fragment, out PS_OUT result )
// proportional to the projected area of the sphere
float ssDiskRadius = -projScale * radius / C.z;
#if 0
#if 1
if( ssDiskRadius <= MIN_RADIUS )
{
// There is no way to compute AO at this radius
@ -366,7 +396,7 @@ void main( PS_IN fragment, out PS_OUT result )
float A = max( 0.0, 1.0 - sum * intensityDivR6 * ( 5.0 / NUM_SAMPLES ) );
// Anti-tone map to reduce contrast and drag dark region farther
// (x^0.2 + 1.2 * x^4)/2.2
A = ( pow( A, 0.2 ) + 1.2 * A * A * A * A ) / 2.2;
//A = ( pow( A, 0.2 ) + 1.2 * A * A * A * A ) / 2.2;
#endif
// Visualize random spin distribution
@ -374,11 +404,13 @@ void main( PS_IN fragment, out PS_OUT result )
// Fade in as the radius reaches 2 pixels
visibility = lerp( 1.0, A, saturate( ssDiskRadius - MIN_RADIUS ) );
//visibility = A;
//result.color = float4( visibility, bilateralKey, 0.0, 1.0 );
//result.color = float4( bilateralKey, bilateralKey, bilateralKey, 1.0 );
result.color = float4( visibility, visibility, visibility, 1.0 );
//result.color = float4( visibility, visibility, visibility, 1.0 );
//result.color = float4( n_C * 0.5 + 0.5, 1.0 );
//result.color = float4( n_C, 1.0 );
//result.color = texture( samp0, fragment.texcoord0 ).rgba;
// derive clip space from the depth buffer and screen position

View file

@ -0,0 +1,345 @@
/**
\file AmbientOcclusion_blur.pix
\author Morgan McGuire and Michael Mara, NVIDIA Research
\brief 7-tap 1D cross-bilateral blur using a packed depth key
DX11 HLSL port by Leonardo Zide, Treyarch
Open Source under the "BSD" license: http://www.opensource.org/licenses/bsd-license.php
Copyright (c) 2011-2012, NVIDIA
Copyright (c) 2016 Robert Beckebans ( id Tech 4.x integration )
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "renderprogs/global.inc"
// *INDENT-OFF*
uniform sampler2D samp0 : register( s0 ); // view color
uniform sampler2D samp1 : register( s1 ); // view depth
#define source samp0
#define CS_Z_buffer samp1
struct PS_IN
{
float2 texcoord0 : TEXCOORD0_centroid;
};
struct PS_OUT
{
float4 color : COLOR;
};
// *INDENT-ON*
//////////////////////////////////////////////////////////////////////////////////////////////
// Tunable Parameters:
//#define NUM_KEY_COMPONENTS 1
// The other parameters in this section must be passed in as macro values
/** Increase to make depth edges crisper. Decrease to reduce flicker. */
#define EDGE_SHARPNESS (1.0)
/** Step in 2-pixel intervals since we already blurred against neighbors in the
first AO pass. This constant can be increased while R decreases to improve
performance at the expense of some dithering artifacts.
Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
unobjectionable after shading was applied but eliminated most temporal incoherence
from using small numbers of sample taps.
*/
#define SCALE (2)
/** Filter radius in pixels. This will be multiplied by SCALE. */
#define R (4)
#define MDB_WEIGHTS 0
//////////////////////////////////////////////////////////////////////////////////////////////
/** Type of data to read from source. This macro allows
the same blur shader to be used on different kinds of input data. */
#define VALUE_TYPE float
/** Swizzle to use to extract the channels of source. This macro allows
the same blur shader to be used on different kinds of input data. */
#define VALUE_COMPONENTS r
#define VALUE_IS_KEY 0
/** Channel encoding the bilateral key value (which must not be the same as VALUE_COMPONENTS) */
#if 0 //NUM_KEY_COMPONENTS == 2
#define KEY_COMPONENTS gb
#else
#define KEY_COMPONENTS g
#endif
//#if __VERSION__ >= 330
// Gaussian coefficients
//const float gaussian[R + 1] =
// float[](0.356642, 0.239400, 0.072410, 0.009869);
// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
// float[]( 0.153170, 0.144893, 0.122649, 0.092902, 0.062970 ); // stddev = 2.0
// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
//#endif
/** (1, 0) or (0, 1)*/
//uniform ivec2 axis;
#define aoResult result.color.VALUE_COMPONENTS
#define keyPassThrough result.color.KEY_COMPONENTS
#if 0 //NUM_KEY_COMPONENTS == 2
/** Returns a number on (0, 1) */
float unpackKey( vec2 p )
{
return p.x * ( 256.0 / 257.0 ) + p.y * ( 1.0 / 257.0 );
}
#else
/** Returns a number on (0, 1) */
float unpackKey( float p )
{
return p;
}
#endif
//uniform float4 projInfo;
float3 reconstructCSPosition( float2 S, float z )
{
float4 P;
P.z = z;
P.xy = S * rpScreenCorrectionFactor.xy;
P.w = 1.0;
float4 csP;
csP.x = dot4( P, rpProjectionMatrixX );
csP.y = dot4( P, rpProjectionMatrixY );
csP.z = dot4( P, rpProjectionMatrixZ );
csP.w = dot4( P, rpProjectionMatrixW );
csP.xyz /= csP.w;
return csP.xyz;
}
//float3 reconstructCSPosition( float2 ssP ) + float2( 0.5 ), P.z, projInfo );
/** Used for preventing AO computation on the sky (at infinite depth) and defining the CS Z to bilateral depth key scaling.
This need not match the real far plane but should not be much more than it.*/
const float FAR_PLANE_Z = -4000.0;
float3 positionFromKey( float key, ivec2 ssC )
{
float z = key * FAR_PLANE_Z;
//float3 C = reconstructCSPosition( vec2( ssC )/* + vec2( 0.5 )*/, z, pInfo );
float3 C = reconstructCSPosition( vec2( ssC ), z );
return C;
}
#if 0 //def normal_notNull
/** Same size as result buffer, do not offset by guard band when reading from it */
uniform sampler2D normal_buffer;
uniform float4 normal_readMultiplyFirst;
uniform float4 normal_readAddSecond;
#endif
float calculateBilateralWeight( float key, float tapKey, ivec2 tapLoc, float3 n_C, float3 C )
{
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
float depthWeight = max( 0.0, 1.0 - ( EDGE_SHARPNESS * 2000.0 ) * abs( tapKey - key ) );
float k_normal = 1.0;
float k_plane = 1.0;
// Prevents blending over creases.
float normalWeight = 1.0;
float planeWeight = 1.0;
#if 0 //def normal_notNull
float3 tapN_C = texelFetch( normal_buffer, tapLoc, 0 ).xyz;
tapN_C = normalize( tapN_C * normal_readMultiplyFirst.xyz + normal_readAddSecond.xyz );
float normalError = 1.0 - dot( tapN_C, n_C ) * k_normal;
normalWeight = max( ( 1.0 - EDGE_SHARPNESS * normalError ), 0.00 );
float lowDistanceThreshold2 = 0.001;
float3 tapC = positionFromKey( tapKey, tapLoc, projInfo );
// Change in position in camera space
float3 dq = C - tapC;
// How far away is this point from the original sample
// in camera space? (Max value is unbounded)
float distance2 = dot( dq, dq );
// How far off the expected plane (on the perpendicular) is this point? Max value is unbounded.
float planeError = max( abs( dot( dq, tapN_C ) ), abs( dot( dq, n_C ) ) );
planeWeight = ( distance2 < lowDistanceThreshold2 ) ? 1.0 :
pow( max( 0.0, 1.0 - EDGE_SHARPNESS * 2.0 * k_plane * planeError / sqrt( distance2 ) ), 2.0 );
#endif
//normalWeight = 1.0;
//planeWeight = 1.0;
return depthWeight * normalWeight * planeWeight;
}
void main( PS_IN fragment, out PS_OUT result )
{
#if 1
if( fragment.texcoord0.x < 0.5 )
{
discard;
}
#endif
//# if __VERSION__ < 330
float gaussian[R + 1];
// if R == 0, we never call this shader
// # if R == 1 // TODO: Actually calculate gaussian weights... this is just Mike winging it here
// gaussian[0] = 0.5;
// gaussian[1] = 0.25;
// # elif R == 2 // TODO: Actually calculate gaussian weights... this is just Mike winging it here
// gaussian[0] = 0.153170;
// gaussian[1] = 0.144893;
// gaussian[2] = 0.122649;
// # elif R == 3 // TODO: We are losing some base weight here...
// gaussian[0] = 0.153170;
// gaussian[1] = 0.144893;
// gaussian[2] = 0.122649;
// gaussian[3] = 0.092902; // stddev = 2.0
// # elif R == 4
gaussian[0] = 0.153170;
gaussian[1] = 0.144893;
gaussian[2] = 0.122649;
gaussian[3] = 0.092902;
gaussian[4] = 0.062970; // stddev = 2.0
// # elif R == 5 // TODO: We are losing some base weight here...
// gaussian[0] = 0.111220;
// gaussian[1] = 0.107798;
// gaussian[2] = 0.098151;
// gaussian[3] = 0.083953;
// gaussian[4] = 0.067458;
// gaussian[5] = 0.050920;
// # elif R == 6
// gaussian[0] = 0.111220;
// gaussian[1] = 0.107798;
// gaussian[2] = 0.098151;
// gaussian[3] = 0.083953;
// gaussian[4] = 0.067458;
// gaussian[5] = 0.050920;
// gaussian[6] = 0.036108;
// # endif
//# endif
ivec2 ssC = ivec2( gl_FragCoord.xy );
float4 temp = texelFetch( source, ssC, 0 );
keyPassThrough = temp.KEY_COMPONENTS;
float key = unpackKey( keyPassThrough );
VALUE_TYPE sum = temp.VALUE_COMPONENTS;
if( key == 1.0 )
{
// Sky pixel (if you aren't using depth keying, disable this test)
aoResult = sum;
return;
}
// Base weight for depth falloff. Increase this for more blurriness,
// decrease it for better edge discrimination
float BASE = gaussian[0];
float totalWeight = BASE;
sum *= totalWeight;
float3 n_C;
#if 0 //def normal_notNull
n_C = normalize( texelFetch( normal_buffer, ssC, 0 ).xyz * normal_readMultiplyFirst.xyz + normal_readAddSecond.xyz );
#endif
float3 C = positionFromKey( key, ssC );
#if MDB_WEIGHTS == 0
for( int r = -R; r <= R; ++r )
{
// We already handled the zero case above. This loop should be unrolled and the static branch optimized out,
// so the IF statement has no runtime cost
if( r != 0 )
{
ivec2 tapLoc = ssC + ivec2( rpJitterTexScale.xy ) * ( r * SCALE );
temp = texelFetch( source, tapLoc, 0 );
float tapKey = unpackKey( temp.KEY_COMPONENTS );
VALUE_TYPE value = temp.VALUE_COMPONENTS;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs( r )];
float bilateralWeight = calculateBilateralWeight( key, tapKey, tapLoc, n_C, C );
weight *= bilateralWeight;
sum += value * weight;
totalWeight += weight;
}
}
#else
float lastBilateralWeight = 9999.0;
for( int r = -1; r >= -R; --r )
{
ivec2 tapLoc = ssC + ivec2( rpJitterTexScale.xy ) * ( r * SCALE );
temp = texelFetch( source, tapLoc, 0 );
float tapKey = unpackKey( temp.KEY_COMPONENTS );
VALUE_TYPE value = temp.VALUE_COMPONENTS;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs( r )];
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
float bilateralWeight = calculateBilateralWeight( key, tapKey, tapLoc, n_C, C );
bilateralWeight = min( lastBilateralWeight, bilateralWeight );
lastBilateralWeight = bilateralWeight;
weight *= bilateralWeight;
sum += value * weight;
totalWeight += weight;
}
lastBilateralWeight = 9999.0;
for( int r = 1; r <= R; ++r )
{
ivec2 tapLoc = ssC + ivec2( rpJitterTexScale.xy ) * ( r * SCALE );
temp = texelFetch( source, tapLoc, 0 );
float tapKey = unpackKey( temp.KEY_COMPONENTS );
VALUE_TYPE value = temp.VALUE_COMPONENTS;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs( r )];
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
float bilateralWeight = calculateBilateralWeight( key, tapKey, tapLoc, n_C, C );
bilateralWeight = min( lastBilateralWeight, bilateralWeight );
lastBilateralWeight = bilateralWeight;
weight *= bilateralWeight;
sum += value * weight;
totalWeight += weight;
}
#endif
const float epsilon = 0.0001;
aoResult = sum / ( totalWeight + epsilon );
//result.color = float4( aoResult, aoResult, aoResult, 1.0 );
}

View file

@ -0,0 +1,47 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "renderprogs/global.inc"
struct VS_IN
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
};
struct VS_OUT
{
float4 position : POSITION;
float2 texcoord0 : TEXCOORD0;
};
void main( VS_IN vertex, out VS_OUT result )
{
result.position = vertex.position;
result.texcoord0 = vertex.texcoord;
}

View file

@ -62,7 +62,7 @@ void main( PS_IN fragment, out PS_OUT result )
localNormal.z = sqrt( 1.0f - dot3( localNormal, localNormal ) );
float3 globalNormal;
#if 1
#if 0
globalNormal.x = dot3( localNormal, fragment.texcoord2 );
globalNormal.y = dot3( localNormal, fragment.texcoord3 );
globalNormal.z = dot3( localNormal, fragment.texcoord4 );
@ -77,5 +77,6 @@ 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;
}

View file

@ -135,7 +135,7 @@ void main( VS_IN vertex, out VS_OUT result ) {
//result.texcoord1.y = dot3( toEye, rpModelMatrixY );
//result.texcoord1.z = dot3( toEye, rpModelMatrixZ );
#if 1
#if 0
// rotate into world space
result.texcoord2.x = dot3( tangent, rpModelMatrixX );
result.texcoord3.x = dot3( tangent, rpModelMatrixY );

View file

@ -2,5 +2,6 @@ astyle.exe -v --formatted --options=astyle-options.ini --exclude="libs" --recurs
astyle.exe -v --formatted --options=astyle-options.ini --exclude="libs" --exclude="d3xp/gamesys/SysCvar.cpp" --exclude="d3xp/gamesys/Callbacks.cpp" --exclude="sys/win32/win_cpu.cpp" --exclude="sys/win32/win_main.cpp" --recursive *.cpp
astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/postprocess.pixel
astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/AmbientOcclusion_AO.pixel
astyle.exe -v -Q --options=astyle-options.ini ../base/renderprogs/AmbientOcclusion_blur.pixel
pause

View file

@ -366,6 +366,7 @@ public:
idImage* smaaEdgesImage;
idImage* smaaBlendImage;
idImage* currentNormalsImage; // cheap G-Buffer replacement, holds normals and surface roughness
idImage* currentAOImage; // contains AO and bilateral filtering keys
// RB end
idImage* scratchImage;
idImage* scratchImage2;

View file

@ -864,6 +864,7 @@ void idImageManager::CreateIntrinsicImages()
smaaBlendImage = globalImages->ImageFromFunction( "_smaaBlend", R_SMAAImage_ResNative );
currentNormalsImage = ImageFromFunction( "_currentNormals", R_RGBA8Image );
currentAOImage = ImageFromFunction( "_currentAO", R_RGBA8Image );
// RB end
// scratchImage is used for screen wipes/doublevision etc..

View file

@ -149,6 +149,7 @@ void idRenderProgManager::Init()
{ BUILTIN_SMAA_NEIGHBORHOOD_BLENDING, "SMAA_final", "", 0, false },
{ BUILTIN_AMBIENT_OCCLUSION, "AmbientOcclusion_AO", "", 0, false },
{ BUILTIN_AMBIENT_OCCLUSION_BLUR, "AmbientOcclusion_blur", "", 0, false },
// RB end
{ BUILTIN_STEREO_DEGHOST, "stereoDeGhost.vfp", 0, false },
{ BUILTIN_STEREO_WARP, "stereoWarp.vfp", 0, false },

View file

@ -458,6 +458,11 @@ public:
BindShader_Builtin( BUILTIN_AMBIENT_OCCLUSION );
}
void BindShader_AmbientOcclusionBlur()
{
BindShader_Builtin( BUILTIN_AMBIENT_OCCLUSION_BLUR );
}
#if 0
void BindShader_ZCullReconstruct()
{
@ -582,6 +587,7 @@ protected:
BUILTIN_SMAA_NEIGHBORHOOD_BLENDING,
BUILTIN_AMBIENT_OCCLUSION,
BUILTIN_AMBIENT_OCCLUSION_BLUR,
// RB end
BUILTIN_STEREO_DEGHOST,
BUILTIN_STEREO_WARP,

View file

@ -4624,9 +4624,34 @@ void RB_SSAO()
SetFragmentParm( RENDERPARM_OVERBRIGHT, samples.ToFloatPtr() );
// RB: set unprojection matrices so we can convert zbuffer values back to camera and world spaces
SetVertexParms( RENDERPARM_MODELMATRIX_X, backEnd.viewDef->unprojectionToWorldRenderMatrix[0], 4 );
idRenderMatrix modelViewMatrix;
idRenderMatrix::Transpose( *( idRenderMatrix* )backEnd.viewDef->worldSpace.modelViewMatrix, modelViewMatrix );
idRenderMatrix cameraToWorldMatrix;
if( !idRenderMatrix::Inverse( modelViewMatrix, cameraToWorldMatrix ) )
{
idLib::Warning( "cameraToWorldMatrix invert failed" );
}
SetVertexParms( RENDERPARM_MODELMATRIX_X, cameraToWorldMatrix[0], 4 );
//SetVertexParms( RENDERPARM_MODELMATRIX_X, backEnd.viewDef->unprojectionToWorldRenderMatrix[0], 4 );
SetVertexParms( RENDERPARM_PROJMATRIX_X, backEnd.viewDef->unprojectionToCameraRenderMatrix[0], 4 );
float jitterTexOffset[4];
if( r_shadowMapRandomizeJitter.GetBool() )
{
jitterTexOffset[0] = ( rand() & 255 ) / 255.0;
jitterTexOffset[1] = ( rand() & 255 ) / 255.0;
}
else
{
jitterTexOffset[0] = 0;
jitterTexOffset[1] = 0;
}
jitterTexOffset[2] = backEnd.viewDef->renderView.time[0] * 0.001f;
jitterTexOffset[3] = 0.0f;
SetFragmentParm( RENDERPARM_JITTERTEXOFFSET, jitterTexOffset ); // rpJitterTexOffset
GL_SelectTexture( 0 );
globalImages->currentNormalsImage->Bind();
@ -4634,6 +4659,45 @@ void RB_SSAO()
globalImages->currentDepthImage->Bind();
RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
// AO blur X
#if 1
renderProgManager.BindShader_AmbientOcclusionBlur();
const idScreenRect& viewport = backEnd.viewDef->viewport;
globalImages->currentAOImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
// set axis parameter
float jitterTexScale[4];
jitterTexScale[0] = 1;
jitterTexScale[1] = 0;
jitterTexScale[2] = 0;
jitterTexScale[3] = 0;
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
GL_SelectTexture( 0 );
globalImages->currentAOImage->Bind();
RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
// AO blur Y
globalImages->currentAOImage->CopyFramebuffer( viewport.x1, viewport.y1, viewport.GetWidth(), viewport.GetHeight() );
// set axis parameter
jitterTexScale[0] = 0;
jitterTexScale[1] = 1;
jitterTexScale[2] = 0;
jitterTexScale[3] = 0;
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
GL_SelectTexture( 0 );
globalImages->currentAOImage->Bind();
RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
#endif
GL_CheckErrors();
}
// RB end