mirror of
https://github.com/lubosz/overte.git
synced 2025-04-11 06:32:09 +02:00
Switched to sin based HBAO
This commit is contained in:
parent
abc415c5ad
commit
7f6c9a6cc1
6 changed files with 135 additions and 52 deletions
|
@ -206,10 +206,10 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
|
|||
|
||||
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
||||
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
|
||||
radius{ 0.3f },
|
||||
radius{ 0.5f },
|
||||
perspectiveScale{ 1.0f },
|
||||
obscuranceLevel{ 0.5f },
|
||||
falloffAngle{ 0.45f },
|
||||
obscuranceLevel{ 0.25f },
|
||||
falloffAngle{ 0.7f },
|
||||
edgeSharpness{ 1.0f },
|
||||
blurDeviation{ 2.5f },
|
||||
numSpiralTurns{ 7.0f },
|
||||
|
@ -227,6 +227,7 @@ AmbientOcclusionEffect::AOParameters::AOParameters() {
|
|||
_radiusInfo = { 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f };
|
||||
_ditheringInfo = { 0.0f, 0.0f, 0.01f, 1.0f };
|
||||
_sampleInfo = { 11.0f, 1.0f / 11.0f, 7.0f, 1.0f };
|
||||
_falloffInfo = { 0.5f, 2.0f, 0.866f, 1.1547f };
|
||||
}
|
||||
|
||||
AmbientOcclusionEffect::BlurParameters::BlurParameters() {
|
||||
|
@ -263,10 +264,13 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
|||
current.w = config.obscuranceLevel;
|
||||
}
|
||||
|
||||
if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) {
|
||||
auto& current = _aoParametersBuffer.edit()._ditheringInfo;
|
||||
current.z = config.falloffAngle;
|
||||
current.y = 1.0f / (1.0f - config.falloffAngle);
|
||||
if (config.falloffAngle != _aoParametersBuffer->getFalloffCosAngle()) {
|
||||
auto& current = _aoParametersBuffer.edit()._falloffInfo;
|
||||
current.x = config.falloffAngle;
|
||||
current.y = 1.0f / (1.0f - current.x);
|
||||
// Compute sin from cos
|
||||
current.z = sqrtf(1.0f - config.falloffAngle * config.falloffAngle);
|
||||
current.w = 1.0f / current.z;
|
||||
}
|
||||
|
||||
// Update bilateral blur
|
||||
|
@ -535,7 +539,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
|
|||
auto& sample = _aoFrameParametersBuffer[splitId].edit();
|
||||
sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId];
|
||||
}
|
||||
_frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT;
|
||||
//_frameId = (_frameId + 1) % SSAO_RANDOM_SAMPLE_COUNT;
|
||||
|
||||
gpu::doInBatch("AmbientOcclusionEffect::run", args->_context, [=](gpu::Batch& batch) {
|
||||
PROFILE_RANGE_BATCH(batch, "SSAO");
|
||||
|
|
|
@ -150,7 +150,7 @@ public:
|
|||
float getRadius() const { return _radiusInfo.x; }
|
||||
float getPerspectiveScale() const { return _resolutionInfo.z; }
|
||||
float getObscuranceLevel() const { return _radiusInfo.w; }
|
||||
float getFalloffAngle() const { return (float)_ditheringInfo.z; }
|
||||
float getFalloffCosAngle() const { return (float)_falloffInfo.x; }
|
||||
|
||||
float getNumSpiralTurns() const { return _sampleInfo.z; }
|
||||
int getNumSamples() const { return (int)_sampleInfo.x; }
|
||||
|
|
|
@ -115,11 +115,18 @@ float isBorderingEnabled() {
|
|||
return params._ditheringInfo.w;
|
||||
}
|
||||
|
||||
float getFalloffAngle() {
|
||||
return params._ditheringInfo.z;
|
||||
float getFalloffCosAngle() {
|
||||
return params._falloffInfo.x;
|
||||
}
|
||||
float getFalloffAngleScale() {
|
||||
return params._ditheringInfo.y;
|
||||
float getFalloffCosAngleScale() {
|
||||
return params._falloffInfo.y;
|
||||
}
|
||||
|
||||
float getFalloffSinAngle() {
|
||||
return params._falloffInfo.z;
|
||||
}
|
||||
float getFalloffSinAngleScale() {
|
||||
return params._falloffInfo.w;
|
||||
}
|
||||
|
||||
float getNumSamples() {
|
||||
|
@ -330,10 +337,27 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU
|
|||
vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV);
|
||||
vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV);
|
||||
|
||||
vec3 fragPositionDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
|
||||
vec3 fragPositionDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);
|
||||
vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
|
||||
vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);
|
||||
|
||||
return normalize( cross(fragPositionDx, fragPositionDy) );
|
||||
return normalize( cross(fragDeltaDx, fragDeltaDy) );
|
||||
}
|
||||
|
||||
void buildTangentBinormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec3 fragNormal, vec2 deltaDepthUV,
|
||||
out vec3 fragTangent, out vec3 fragBinormal) {
|
||||
vec3 fragPositionDxPos = buildPosition(side, fragUVPos, ivec2(1,0), deltaDepthUV);
|
||||
vec3 fragPositionDxNeg = buildPosition(side, fragUVPos, ivec2(-1,0), deltaDepthUV);
|
||||
vec3 fragPositionDyPos = buildPosition(side, fragUVPos, ivec2(0,1), deltaDepthUV);
|
||||
vec3 fragPositionDyNeg = buildPosition(side, fragUVPos, ivec2(0,-1), deltaDepthUV);
|
||||
|
||||
vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
|
||||
vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);
|
||||
|
||||
//fragTangent = normalize( cross(fragDeltaDy, fragNormal) );
|
||||
//fragBinormal = normalize( cross(fragNormal, fragDeltaDx) );
|
||||
|
||||
fragTangent = fragDeltaDx;
|
||||
fragBinormal = fragDeltaDy;
|
||||
}
|
||||
|
||||
<@endfunc@>
|
||||
|
@ -341,6 +365,12 @@ vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthU
|
|||
|
||||
<@func declareEvalObscurance()@>
|
||||
|
||||
struct TBNFrame {
|
||||
vec3 tangent;
|
||||
vec3 binormal;
|
||||
vec3 normal;
|
||||
};
|
||||
|
||||
vec3 fastAcos(vec3 x) {
|
||||
// [Eberly2014] GPGPU Programming for Games and Science
|
||||
vec3 absX = abs(x);
|
||||
|
@ -357,29 +387,25 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t
|
|||
// Falloff function as recommended in SSAO paper
|
||||
const float epsilon = 0.01;
|
||||
float f = max(getRadius2() - vv, 0.0);
|
||||
return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0);
|
||||
return f * f * f * max((vn - getFalloffCosAngle()) / (epsilon + vv), 0.0);
|
||||
}
|
||||
|
||||
vec2 computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) {
|
||||
const float epsilon = 0.001;
|
||||
#define HBAO_USE_COS_ANGLE 0
|
||||
|
||||
vec3 deltaVec = tapPositionES - fragPositionES;
|
||||
float distance = length(deltaVec);
|
||||
float cosHorizonAngle = dot(deltaVec, fragNormalES) / (distance + epsilon);
|
||||
float computeWeightedHorizon(float horizonLimit, float distanceSquared) {
|
||||
float radiusFalloff = distanceSquared / getRadius2();
|
||||
|
||||
return vec2(cosHorizonAngle, distance);
|
||||
}
|
||||
radiusFalloff = max(0.0, 1.0 - radiusFalloff);
|
||||
|
||||
float computeWeightedHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES) {
|
||||
vec2 rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES);
|
||||
float distance = rawHorizon.y;
|
||||
float cosHorizonAngle = rawHorizon.x;
|
||||
float radiusFalloff = max(0.0, 1.0 - (distance*distance / getRadius2()));
|
||||
#if !HBAO_USE_COS_ANGLE
|
||||
horizonLimit = getFalloffSinAngle() - horizonLimit;
|
||||
#endif
|
||||
horizonLimit *= radiusFalloff;
|
||||
#if !HBAO_USE_COS_ANGLE
|
||||
horizonLimit = getFalloffSinAngle() - horizonLimit;
|
||||
#endif
|
||||
|
||||
cosHorizonAngle = max(0.0, (cosHorizonAngle - getFalloffAngle()) * getFalloffAngleScale());
|
||||
cosHorizonAngle *= radiusFalloff;
|
||||
|
||||
return cosHorizonAngle;
|
||||
return horizonLimit;
|
||||
}
|
||||
|
||||
<@func computeHorizon()@>
|
||||
|
@ -389,24 +415,46 @@ float computeWeightedHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec
|
|||
}
|
||||
vec2 tapMipZ = fetchTap(side, fragUVPos, radius);
|
||||
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, fragUVPos);
|
||||
float tapCosHorizonAngle = computeWeightedHorizonFromTap(tapPositionES, fragPositionES, fragNormalES);
|
||||
vec3 deltaVec = tapPositionES - fragPositionES;
|
||||
float distanceSquared = dot(deltaVec, deltaVec);
|
||||
float distance = sqrt(distanceSquared);
|
||||
float deltaDotNormal = dot(deltaVec, fragFrameES.normal);
|
||||
#if HBAO_USE_COS_ANGLE
|
||||
float tapHorizonLimit = deltaDotNormal;
|
||||
#else
|
||||
float tapHorizonLimit = dot(deltaVec, fragFrameES.tangent);
|
||||
#endif
|
||||
float epsilon = 0.0001;
|
||||
tapHorizonLimit /= (distance + epsilon);
|
||||
|
||||
cosHorizonAngle = max(cosHorizonAngle, tapCosHorizonAngle);
|
||||
|
||||
if (distanceSquared < getRadius2() && deltaDotNormal>0.0 &&
|
||||
#if HBAO_USE_COS_ANGLE
|
||||
tapHorizonLimit > horizonLimit
|
||||
#else
|
||||
tapHorizonLimit < horizonLimit
|
||||
#endif
|
||||
) {
|
||||
tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared);
|
||||
#if HBAO_USE_COS_ANGLE
|
||||
horizonLimit = max(horizonLimit, tapHorizonLimit);
|
||||
#else
|
||||
horizonLimit = min(horizonLimit, tapHorizonLimit);
|
||||
#endif
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
#define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0
|
||||
|
||||
float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragNormalES, vec2 searchVec, vec2 pixelSearchVec,
|
||||
float searchRadius) {
|
||||
float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchVec, float searchRadius, int stepCount) {
|
||||
vec2 absSearchVec = abs(searchVec);
|
||||
pixelSearchVec = abs(pixelSearchVec);
|
||||
int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y)));
|
||||
float cosHorizonAngle = 0.0;
|
||||
#if HBAO_USE_COS_ANGLE
|
||||
float horizonLimit = getFalloffCosAngle();
|
||||
#else
|
||||
float horizonLimit = getFalloffSinAngle();
|
||||
#endif
|
||||
|
||||
if (stepCount>0) {
|
||||
vec2 deltaTapUV = searchVec / float(stepCount);
|
||||
|
||||
float deltaRadius = searchRadius / float(stepCount);
|
||||
|
||||
#if HBAO_HORIZON_SEARCH_CONSTANT_STEP
|
||||
|
@ -439,22 +487,33 @@ float computeHorizon(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, vec3 fragN
|
|||
#endif
|
||||
}
|
||||
|
||||
return cosHorizonAngle;
|
||||
return horizonLimit;
|
||||
}
|
||||
|
||||
float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius,
|
||||
vec3 fragPositionES, vec3 fragNormalES) {
|
||||
vec3 fragPositionES, TBNFrame fragFrameES) {
|
||||
vec2 pixelSearchVec = deltaTap * diskPixelRadius;
|
||||
vec2 searchVec = pixelSearchVec * invSideImageSize;
|
||||
float obscurance = 0.0;
|
||||
float obscuranceH1 = 0.0;
|
||||
float obscuranceH2 = 0.0;
|
||||
|
||||
#if !HBAO_USE_COS_ANGLE
|
||||
fragFrameES.tangent = normalize(fragFrameES.tangent * deltaTap.x + fragFrameES.binormal * deltaTap.y);
|
||||
#endif
|
||||
|
||||
pixelSearchVec = abs(pixelSearchVec);
|
||||
int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y)));
|
||||
|
||||
// Forward search for h1
|
||||
obscurance = computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, searchVec, pixelSearchVec, diskPixelRadius);
|
||||
obscuranceH1 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, searchVec, diskPixelRadius, stepCount);
|
||||
|
||||
// Backward search for h2
|
||||
obscurance += computeHorizon(side, fragUVPos, fragPositionES, fragNormalES, -searchVec, pixelSearchVec, diskPixelRadius);
|
||||
#if !HBAO_USE_COS_ANGLE
|
||||
fragFrameES.tangent = -fragFrameES.tangent;
|
||||
#endif
|
||||
obscuranceH2 = computeHorizon(side, fragUVPos, fragPositionES, fragFrameES, -searchVec, diskPixelRadius, stepCount);
|
||||
|
||||
return obscurance;
|
||||
return obscuranceH1 + obscuranceH2;
|
||||
}
|
||||
|
||||
<@endfunc@>
|
||||
|
|
|
@ -55,6 +55,15 @@ void main(void) {
|
|||
diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS);
|
||||
}
|
||||
|
||||
TBNFrame fragFrameES;
|
||||
|
||||
fragFrameES.tangent = vec3(0.0);
|
||||
fragFrameES.binormal = vec3(0.0);
|
||||
fragFrameES.normal = fragNormalES;
|
||||
#if !HBAO_USE_COS_ANGLE
|
||||
buildTangentBinormal(side, fragUVPos, fragPositionES, fragNormalES, deltaDepthUV, fragFrameES.tangent, fragFrameES.binormal);
|
||||
#endif
|
||||
|
||||
// Let's make noise
|
||||
float randomPatternRotationAngle = getAngleDithering(fragPixelPos);
|
||||
|
||||
|
@ -66,9 +75,18 @@ void main(void) {
|
|||
if (isHorizonBased()) {
|
||||
for (int i = 0; i < numSamples; ++i) {
|
||||
vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI);
|
||||
obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragNormalES);
|
||||
obscuranceSum += evalVisibilityHBAO(side, fragUVPos, deltaDepthUV, deltaTap.xy, diskPixelRadius, fragPositionES, fragFrameES);
|
||||
}
|
||||
obscuranceSum *= invNumSamples;
|
||||
#if HBAO_USE_COS_ANGLE
|
||||
obscuranceSum *= 0.5 / PI;
|
||||
obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling();
|
||||
#else
|
||||
obscuranceSum *= 0.5;
|
||||
obscuranceSum += 1.0 - getFalloffSinAngle();
|
||||
|
||||
obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling());
|
||||
#endif
|
||||
} else {
|
||||
// Steps are in the depth texture resolution
|
||||
vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize;
|
||||
|
@ -80,10 +98,11 @@ void main(void) {
|
|||
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV);
|
||||
obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES);
|
||||
}
|
||||
obscuranceSum *= invNumSamples;
|
||||
obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling();
|
||||
}
|
||||
|
||||
obscuranceSum *= getObscuranceScaling() * invNumSamples;
|
||||
float occlusion = clamp(1.0 - obscuranceSum * obscuranceSum, 0.0, 1.0);
|
||||
float occlusion = clamp(obscuranceSum, 0.0, 1.0);
|
||||
|
||||
outFragColor = packOcclusionOutput(occlusion, fragPositionES.z, fragNormalES);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ struct AmbientOcclusionParams {
|
|||
SSAO_VEC4 _radiusInfo;
|
||||
SSAO_VEC4 _ditheringInfo;
|
||||
SSAO_VEC4 _sampleInfo;
|
||||
SSAO_VEC4 _falloffInfo;
|
||||
SSAO_VEC4 _sideSizes[2];
|
||||
};
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ Rectangle {
|
|||
"Level:obscuranceLevel:1.0:false",
|
||||
"Num Taps:numSamples:16:true",
|
||||
"Taps Spiral:numSpiralTurns:10.0:false",
|
||||
"Falloff Angle:falloffAngle:0.5:false",
|
||||
"Falloff Angle:falloffAngle:1.0:false",
|
||||
"Blur Edge Sharpness:edgeSharpness:1.0:false",
|
||||
"Blur Radius:blurRadius:15.0:true",
|
||||
"Resolution Downscale:resolutionLevel:2:true",
|
||||
|
|
Loading…
Reference in a new issue