mirror of
https://github.com/overte-org/overte.git
synced 2025-08-13 06:18:39 +02:00
HBAO implementation ported from NVidia HLSL
This commit is contained in:
parent
34e400ac67
commit
d76cda396f
1 changed files with 258 additions and 1 deletions
|
@ -17,7 +17,7 @@
|
|||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
/*
|
||||
varying vec2 varTexcoord;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
|
@ -105,5 +105,262 @@ void main(void) {
|
|||
occlusion = 1.0 - occlusion / float(SAMPLE_COUNT);
|
||||
occlusion = clamp(pow(occlusion, g_intensity), 0.0, 1.0);
|
||||
gl_FragColor = vec4(vec3(occlusion), 1.0);
|
||||
}*/
|
||||
|
||||
// This is a HBAO-Shader for OpenGL, based upon nvidias directX implementation
|
||||
// supplied in their SampleSDK available from nvidia.com
|
||||
// The slides describing the implementation is available at
|
||||
// http://www.nvidia.co.uk/object/siggraph-2008-HBAO.html
|
||||
|
||||
varying vec2 varTexcoord;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
|
||||
uniform float g_scale;
|
||||
uniform float g_bias;
|
||||
uniform float g_sample_rad;
|
||||
uniform float g_intensity;
|
||||
uniform float bufferWidth;
|
||||
uniform float bufferHeight;
|
||||
|
||||
const float PI = 3.14159265;
|
||||
|
||||
const vec2 FocalLen = vec2(1.0, 1.0);
|
||||
//const vec2 UVToViewA = vec2(1.0, 1.0);
|
||||
//const vec2 UVToViewB = vec2(1.0, 1.0);
|
||||
|
||||
const vec2 LinMAD = vec2(0.1-10.0, 0.1+10.0) / (2.0*0.1*10.0);
|
||||
|
||||
const vec2 AORes = vec2(1024.0, 768.0);
|
||||
const vec2 InvAORes = vec2(1.0/1024.0, 1.0/768.0);
|
||||
const vec2 NoiseScale = vec2(1024.0, 768.0) / 4.0;
|
||||
|
||||
const float AOStrength = 1.9;
|
||||
const float R = 0.3;
|
||||
const float R2 = 0.3*0.3;
|
||||
const float NegInvR2 = - 1.0 / (0.3*0.3);
|
||||
const float TanBias = tan(30.0 * PI / 180.0);
|
||||
const float MaxRadiusPixels = 100.0;
|
||||
|
||||
const int NumDirections = 6;
|
||||
const int NumSamples = 4;
|
||||
|
||||
float ViewSpaceZFromDepth(float d)
|
||||
{
|
||||
// [0,1] -> [-1,1] clip space
|
||||
d = d * 2.0 - 1.0;
|
||||
|
||||
// Get view space Z
|
||||
return -1.0 / (LinMAD.x * d + LinMAD.y);
|
||||
}
|
||||
|
||||
vec3 UVToViewSpace(vec2 uv, float z)
|
||||
{
|
||||
//uv = UVToViewA * uv + UVToViewB;
|
||||
return vec3(uv * z, z);
|
||||
}
|
||||
|
||||
vec3 GetViewPos(vec2 uv)
|
||||
{
|
||||
float z = ViewSpaceZFromDepth(texture2D(depthTexture, uv).r);
|
||||
return UVToViewSpace(uv, z);
|
||||
}
|
||||
|
||||
vec3 GetViewPosPoint(ivec2 uv)
|
||||
{
|
||||
vec2 coord = vec2(gl_FragCoord.xy) + uv;
|
||||
//float z = texelFetch(texture0, coord, 0).r;
|
||||
float z = texture2D(depthTexture, uv).r;
|
||||
return UVToViewSpace(uv, z);
|
||||
}
|
||||
|
||||
float TanToSin(float x)
|
||||
{
|
||||
return x * inversesqrt(x*x + 1.0);
|
||||
}
|
||||
|
||||
float InvLength(vec2 V)
|
||||
{
|
||||
return inversesqrt(dot(V,V));
|
||||
}
|
||||
|
||||
float Tangent(vec3 V)
|
||||
{
|
||||
return V.z * InvLength(V.xy);
|
||||
}
|
||||
|
||||
float BiasedTangent(vec3 V)
|
||||
{
|
||||
return V.z * InvLength(V.xy) + TanBias;
|
||||
}
|
||||
|
||||
float Tangent(vec3 P, vec3 S)
|
||||
{
|
||||
return -(P.z - S.z) * InvLength(S.xy - P.xy);
|
||||
}
|
||||
|
||||
float Length2(vec3 V)
|
||||
{
|
||||
return dot(V,V);
|
||||
}
|
||||
|
||||
vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl)
|
||||
{
|
||||
vec3 V1 = Pr - P;
|
||||
vec3 V2 = P - Pl;
|
||||
return (Length2(V1) < Length2(V2)) ? V1 : V2;
|
||||
}
|
||||
|
||||
vec2 SnapUVOffset(vec2 uv)
|
||||
{
|
||||
return round(uv * AORes) * InvAORes;
|
||||
}
|
||||
|
||||
float Falloff(float d2)
|
||||
{
|
||||
return d2 * NegInvR2 + 1.0f;
|
||||
}
|
||||
|
||||
float HorizonOcclusion( vec2 deltaUV,
|
||||
vec3 P,
|
||||
vec3 dPdu,
|
||||
vec3 dPdv,
|
||||
float randstep,
|
||||
float numSamples)
|
||||
{
|
||||
float ao = 0;
|
||||
|
||||
// Offset the first coord with some noise
|
||||
vec2 uv = varTexcoord + SnapUVOffset(randstep*deltaUV);
|
||||
deltaUV = SnapUVOffset( deltaUV );
|
||||
|
||||
// Calculate the tangent vector
|
||||
vec3 T = deltaUV.x * dPdu + deltaUV.y * dPdv;
|
||||
|
||||
// Get the angle of the tangent vector from the viewspace axis
|
||||
float tanH = BiasedTangent(T);
|
||||
float sinH = TanToSin(tanH);
|
||||
|
||||
float tanS;
|
||||
float d2;
|
||||
vec3 S;
|
||||
|
||||
// Sample to find the maximum angle
|
||||
for(float s = 1; s <= numSamples; ++s)
|
||||
{
|
||||
uv += deltaUV;
|
||||
S = GetViewPos(uv);
|
||||
tanS = Tangent(P, S);
|
||||
d2 = Length2(S - P);
|
||||
|
||||
// Is the sample within the radius and the angle greater?
|
||||
if(d2 < R2 && tanS > tanH)
|
||||
{
|
||||
float sinS = TanToSin(tanS);
|
||||
// Apply falloff based on the distance
|
||||
ao += Falloff(d2) * (sinS - sinH);
|
||||
|
||||
tanH = tanS;
|
||||
sinH = sinS;
|
||||
}
|
||||
}
|
||||
|
||||
return ao;
|
||||
}
|
||||
|
||||
vec2 RotateDirections(vec2 Dir, vec2 CosSin)
|
||||
{
|
||||
return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y,
|
||||
Dir.x*CosSin.y + Dir.y*CosSin.x);
|
||||
}
|
||||
|
||||
void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand)
|
||||
{
|
||||
// Avoid oversampling if numSteps is greater than the kernel radius in pixels
|
||||
numSteps = min(NumSamples, rayRadiusPix);
|
||||
|
||||
// Divide by Ns+1 so that the farthest samples are not fully attenuated
|
||||
float stepSizePix = rayRadiusPix / (numSteps + 1);
|
||||
|
||||
// Clamp numSteps if it is greater than the max kernel footprint
|
||||
float maxNumSteps = MaxRadiusPixels / stepSizePix;
|
||||
if (maxNumSteps < numSteps)
|
||||
{
|
||||
// Use dithering to avoid AO discontinuities
|
||||
numSteps = floor(maxNumSteps + rand);
|
||||
numSteps = max(numSteps, 1);
|
||||
stepSizePix = MaxRadiusPixels / numSteps;
|
||||
}
|
||||
|
||||
// Step size in uv space
|
||||
stepSizeUv = stepSizePix * InvAORes;
|
||||
}
|
||||
|
||||
float getRandom(vec2 uv) {
|
||||
return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
float numDirections = NumDirections;
|
||||
|
||||
vec3 P, Pr, Pl, Pt, Pb;
|
||||
P = GetViewPos(varTexcoord);
|
||||
|
||||
// Sample neighboring pixels
|
||||
Pr = GetViewPos(varTexcoord + vec2( InvAORes.x, 0));
|
||||
Pl = GetViewPos(varTexcoord + vec2(-InvAORes.x, 0));
|
||||
Pt = GetViewPos(varTexcoord + vec2( 0, InvAORes.y));
|
||||
Pb = GetViewPos(varTexcoord + vec2( 0,-InvAORes.y));
|
||||
|
||||
// Calculate tangent basis vectors using the minimu difference
|
||||
vec3 dPdu = MinDiff(P, Pr, Pl);
|
||||
vec3 dPdv = MinDiff(P, Pt, Pb) * (AORes.y * InvAORes.x);
|
||||
|
||||
// Get the random samples from the noise texture
|
||||
vec3 random = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx));
|
||||
|
||||
// Calculate the projected size of the hemisphere
|
||||
vec2 rayRadiusUV = 0.5 * R * FocalLen / -P.z;
|
||||
float rayRadiusPix = rayRadiusUV.x * AORes.x;
|
||||
|
||||
float ao = 1.0;
|
||||
|
||||
// Make sure the radius of the evaluated hemisphere is more than a pixel
|
||||
if(rayRadiusPix > 1.0)
|
||||
{
|
||||
ao = 0.0;
|
||||
float numSteps;
|
||||
vec2 stepSizeUV;
|
||||
|
||||
// Compute the number of steps
|
||||
ComputeSteps(stepSizeUV, numSteps, rayRadiusPix, random.z);
|
||||
|
||||
float alpha = 2.0 * PI / numDirections;
|
||||
|
||||
// Calculate the horizon occlusion of each direction
|
||||
for(float d = 0; d < numDirections; ++d)
|
||||
{
|
||||
float theta = alpha * d;
|
||||
|
||||
// Apply noise to the direction
|
||||
vec2 dir = RotateDirections(vec2(cos(theta), sin(theta)), random.xy);
|
||||
vec2 deltaUV = dir * stepSizeUV;
|
||||
|
||||
// Sample the pixels along the direction
|
||||
ao += HorizonOcclusion( deltaUV,
|
||||
P,
|
||||
dPdu,
|
||||
dPdv,
|
||||
random.z,
|
||||
numSteps);
|
||||
}
|
||||
|
||||
// Average the results and produce the final AO
|
||||
ao = 1.0 - ao / numDirections * AOStrength;
|
||||
}
|
||||
|
||||
//out_frag0 = vec2(ao, 30.0 * P.z);
|
||||
gl_FragColor = vec4(vec3(ao), 1.0);
|
||||
}
|
Loading…
Reference in a new issue