Added some tweaking parameters to try to limit silhouette AO

This commit is contained in:
Olivier Prat 2018-09-13 18:39:02 +02:00
parent 8006d7c052
commit 6b8f47c75a
5 changed files with 97 additions and 104 deletions

View file

@ -181,8 +181,12 @@ AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
#endif
perspectiveScale{ 1.0f },
obscuranceLevel{ 0.5f },
falloffBias{ 0.01f },
silhouetteRadius{ 0.3f },
#if SSAO_USE_HORIZON_BASED
falloffAngle{ 0.1f },
#else
falloffAngle{ 0.01f },
#endif
falloffDistance{ 0.3f },
edgeSharpness{ 1.0f },
blurDeviation{ 2.5f },
numSpiralTurns{ 7.0f },
@ -234,9 +238,9 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = config.obscuranceLevel;
}
if (config.falloffBias != _aoParametersBuffer->getFalloffBias()) {
if (config.falloffAngle != _aoParametersBuffer->getFalloffAngle()) {
auto& current = _aoParametersBuffer.edit().ditheringInfo;
current.z = config.falloffBias;
current.z = config.falloffAngle;
}
if (config.edgeSharpness != _aoParametersBuffer->getEdgeSharpness()) {
@ -297,9 +301,9 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = (float)config.borderingEnabled;
}
if (config.silhouetteRadius != _aoParametersBuffer->getSilhouetteRadius()) {
if (config.falloffDistance != _aoParametersBuffer->getFalloffDistance()) {
auto& current = _aoParametersBuffer.edit().ditheringInfo;
current.y = (float)config.silhouetteRadius;
current.y = (float)config.falloffDistance;
}
if (shouldUpdateGaussian) {
@ -450,6 +454,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
#endif
batch.popProfileRange();
batch.pushProfileRange("Occlusion");
batch.setUniformBuffer(render_utils::slot::buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
batch.setUniformBuffer(render_utils::slot::buffer::SsaoParams, _aoParametersBuffer);
@ -459,10 +464,11 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setPipeline(occlusionPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, _framebuffer->getLinearDepthTexture());
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.popProfileRange();
/* TEMPO OP if (_aoParametersBuffer->getBlurRadius() > 0)*/ {
PROFILE_RANGE_BATCH(batch, "Blur");
// Blur 1st pass
{
PROFILE_RANGE_BATCH(batch, "Bilateral Blur");
// Blur 1st pass
model.setScale(resolutionScale);
batch.setModelTransform(model);
batch.setViewportTransform(firstBlurViewport);
@ -482,8 +488,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, occlusionBlurredFBO->getRenderBuffer(0));
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
batch.setResourceTexture(render_utils::slot::texture::SsaoPyramid, nullptr);
batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, nullptr);

View file

@ -62,8 +62,8 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty)
Q_PROPERTY(float radius MEMBER radius WRITE setRadius)
Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel)
Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias)
Q_PROPERTY(float silhouetteRadius MEMBER silhouetteRadius WRITE setSilhouetteRadius)
Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle)
Q_PROPERTY(float falloffDistance MEMBER falloffDistance WRITE setFalloffDistance)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation)
Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns)
@ -75,12 +75,12 @@ public:
AmbientOcclusionEffectConfig();
const int MAX_RESOLUTION_LEVEL = 4;
const int MAX_BLUR_RADIUS = 6;
const int MAX_BLUR_RADIUS = 15;
void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); }
void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); }
void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); }
void setSilhouetteRadius(float value) { silhouetteRadius = std::max(0.0f, value); emit dirty(); }
void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); }
void setFalloffDistance(float value) { falloffDistance = std::max(0.0f, value); emit dirty(); }
void setEdgeSharpness(float sharpness) { edgeSharpness = std::max(0.0f, (float)sharpness); emit dirty(); }
void setBlurDeviation(float deviation) { blurDeviation = std::max(0.0f, deviation); emit dirty(); }
void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); }
@ -91,8 +91,8 @@ public:
float radius;
float perspectiveScale;
float obscuranceLevel; // intensify or dim down the obscurance effect
float falloffBias;
float silhouetteRadius;
float falloffAngle;
float falloffDistance;
float edgeSharpness;
float blurDeviation;
float numSpiralTurns; // defining an angle span to distribute the samples ray directions
@ -134,7 +134,7 @@ public:
// Blurring info
glm::vec4 blurInfo;
// gaussian distribution coefficients first is the sampling radius (max is 6)
const static int GAUSSIAN_COEFS_LENGTH = 8;
const static int GAUSSIAN_COEFS_LENGTH = 16;
float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH];
AOParameters();
@ -143,10 +143,10 @@ public:
float getRadius() const { return radiusInfo.x; }
float getPerspectiveScale() const { return resolutionInfo.z; }
float getObscuranceLevel() const { return radiusInfo.w; }
float getFalloffBias() const { return (float)ditheringInfo.z; }
float getFalloffAngle() const { return (float)ditheringInfo.z; }
float getFalloffDistance() const { return ditheringInfo.y; }
float getEdgeSharpness() const { return (float)blurInfo.x; }
float getBlurDeviation() const { return blurInfo.z; }
float getSilhouetteRadius() const { return ditheringInfo.y; }
float getNumSpiralTurns() const { return sampleInfo.z; }
int getNumSamples() const { return (int)sampleInfo.x; }

View file

@ -41,7 +41,7 @@ struct AmbientOcclusionParams {
vec4 _ditheringInfo;
vec4 _sampleInfo;
vec4 _blurInfo;
float _gaussianCoefs[8];
float _gaussianCoefs[16];
};
layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer {
@ -75,14 +75,14 @@ float getObscuranceScaling() {
float isDitheringEnabled() {
return params._ditheringInfo.x;
}
float getSilhouetteRadius() {
float getFalloffDistance() {
return params._ditheringInfo.y;
}
float isBorderingEnabled() {
return params._ditheringInfo.w;
}
float getFalloffBias() {
float getFalloffAngle() {
return params._ditheringInfo.z;
}
@ -226,7 +226,7 @@ float getZEyeAtUV(vec2 texCoord, int level) {
return -texture(pyramidMap, texCoord, level).x;
}
const int LOG_MAX_OFFSET = 3;
const int LOG_MAX_OFFSET = 1;
const int MAX_MIP_LEVEL = 5;
int evalMipFromRadius(float radius) {
// mipLevel = floor(log(ssR / MAX_OFFSET));
@ -249,7 +249,7 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
return P;
}
vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
vec4 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips()));
vec2 ssP = tap.xy + vec2(ssC);
@ -259,15 +259,13 @@ vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y);
vec3 P;
vec4 P;
P.xy = tapUV;
P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x;
P.w = float(mipLevel);
P.z = -textureLod(pyramidMap, fetchUV, P.w).x;
return P;
}
<@endfunc@>
@ -289,59 +287,63 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t
// Fall off function as recommended in SSAO paper
const float epsilon = 0.01;
float f = max(getRadius2() - vv, 0.0);
return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0);
return f * f * f * max((vn - getFalloffAngle()) / (epsilon + vv), 0.0);
}
float computeHorizonFromTap(vec3 tapPositionES, vec3 fragPositionES, vec3 fragNormalES, float normalizedRadius) {
vec3 deltaVec = tapPositionES - fragPositionES;
float distance = abs(deltaVec.z);
float rawHorizon = dot(normalize(deltaVec), fragNormalES);
rawHorizon = (rawHorizon - getFalloffAngle()) / (1.0 - getFalloffAngle());
rawHorizon *= 1.0 - normalizedRadius * normalizedRadius;
rawHorizon *= 1.0 - smoothstep(getFalloffDistance()/2, getFalloffDistance(), distance);
return rawHorizon;
}
<@func computeHorizon()@>
vec3 tap = vec3(tapPixelPos, radius);
vec4 tapUVZ_mip = fetchTap(side, centerPixelPos, tap, imageSize);
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ_mip.z, tapUVZ_mip.xy);
float rawHorizon = computeHorizonFromTap(tapPositionES, fragPositionES, fragNormalES, radius / searchRadius);
<$horizon$> = max(<$horizon$>, rawHorizon);
<@endfunc@>
#define SSAO_LINEAR_SAMPLING 0
<@func updateHorizon(horizon, deltaPixelTap)@>
{
int stepIndex;
vec2 tapPixelPos = vec2(0);
float radius = 0.0;
for (stepIndex=stepCount ; stepIndex>0 ; stepIndex--) {
tapPixelPos += deltaPixelTap;
#if !SSAO_LINEAR_SAMPLING
float radius = deltaRadius;
float mipLevel = evalMipFromRadius(radius * float(doFetchMips()));
while (radius<searchRadius) {
tapPixelPos += <$deltaPixelTap$>;
<$computeHorizon()$>
if (tapUVZ_mip.w != mipLevel) {
mipLevel = tapUVZ_mip.w;
deltaRadius *= 2;
<$deltaPixelTap$> *= 2;
}
radius += deltaRadius;
}
#else
float radius = 0.0;
int stepIndex;
for (stepIndex=0 ; stepIndex<stepCount ; stepIndex++) {
tapPixelPos += <$deltaPixelTap$>;
radius += deltaRadius;
vec3 tap = vec3(tapPixelPos, radius);
vec3 tapUVZ = fetchTap(side, centerPixelPos, tap, imageSize);
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
vec3 deltaVec = tapPositionES - fragPositionES;
float deltaVecHeight = dot(deltaVec, fragNormalES);
float rawHorizon = dot(normalize(deltaVec), fragNormalES);
float falloff = max(0.0, 1.0 - deltaVecHeight / getSilhouetteRadius());
rawHorizon = rawHorizon < getFalloffBias() ? 0.0f : rawHorizon;
rawHorizon *= falloff * falloff;
<$horizon$> = max(<$horizon$>, rawHorizon);
<$computeHorizon()$>
}
}
<@endfunc@>
<@func searchBresenhamHorizon(deltaPixelCoord)@>
{
float epsilon = 1e-8;
vec2 deltaPixelTap = searchVec / absSearchVec.<$deltaPixelCoord$>;
vec2 absDeltaPixelTap = abs(deltaPixelTap);
bvec2 nullDelta = absDeltaPixelTap < epsilon;
pixelDelta1 = mix(pixelDelta1, vec2(1.0), pixelDelta1 < epsilon && nullDelta);
pixelDelta2 = mix(pixelDelta2, vec2(1.0), pixelDelta2 < epsilon && nullDelta);
pixelDelta1 = ceil(pixelDelta1 / absDeltaPixelTap);
pixelDelta2 = ceil(pixelDelta2 / absDeltaPixelTap);
int maxStepCount = max(0, int(ceil(absSearchVec.<$deltaPixelCoord$>)));
float deltaRadius = ssDiskRadius / maxStepCount;
int stepCount;
// Forward search for h1
stepCount = clamp(int(min(pixelDelta1.x, pixelDelta1.y)), 0, maxStepCount);
<$updateHorizon(horizons.x, deltaPixelTap)$>
// Backward search for h2
stepCount = clamp(int(min(pixelDelta2.x, pixelDelta2.y)), 0, maxStepCount);
<$updateHorizon(horizons.y, -deltaPixelTap)$>
#endif
}
<@endfunc@>
@ -379,7 +381,8 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta
int stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y));
if (stepCount>0) {
vec2 deltaPixelTap = clampedSearchVec / float(stepCount);
float deltaRadius = length(deltaPixelTap);
float searchRadius = length(clampedSearchVec);
float deltaRadius = searchRadius / float(stepCount);
<$updateHorizon(horizons.x, deltaPixelTap)$>
}
// Backward search for h2
@ -388,32 +391,11 @@ vec2 searchHorizons(ivec4 side, ivec2 centerPixelPos, vec2 imageSize, vec2 delta
stepCount = int(max(absClampedSearchVec.x, absClampedSearchVec.y));
if (stepCount>0) {
vec2 deltaPixelTap = clampedSearchVec / float(stepCount);
float deltaRadius = length(deltaPixelTap);
float searchRadius = length(clampedSearchVec);
float deltaRadius = searchRadius / float(stepCount);
<$updateHorizon(horizons.y, deltaPixelTap)$>
}
//
// <!
//
/* TEMPO OP
// Bresenham style walk along segment
if (absSearchVec.x > absSearchVec.y) {
<$searchBresenhamHorizon(x)$>
} else {
<$searchBresenhamHorizon(y)$>
}
vec3 angles = acos(vec3(horizons, fragNormalES.z)) - PI/2.0;
angles.x = -angles.x;
// Clamp to limit horizon defined by normal plane
horizons.xy = angles.zz + max(angles.xy - angles.zz, vec2(-PI/2.0, PI/2.0));
*/
//
// !>
//
return horizons;
}
@ -460,7 +442,7 @@ float fetchOcclusion(vec2 coords) {
}
const float BLUR_WEIGHT_OFFSET = 0.01;
const float BLUR_EDGE_SCALE = 10.0;
const float BLUR_EDGE_SCALE = 300.0;
vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float key) {
ivec2 tapOffset = <$axis$> * r;
@ -479,7 +461,9 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe
float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r));
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key));
// weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapDepth - key));
float zDistance = tapDepth - key;
weight *= exp(-(getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * zDistance * zDistance);
return vec2(tapOcclusion * weight, weight);
}

View file

@ -20,6 +20,7 @@
<$declarePackOcclusionDepth()$>
#define SSAO_USE_HORIZON_BASED 1
#define SSAO_HBAO_MAX_RADIUS 100.0
layout(location=0) out vec4 outFragColor;
@ -46,6 +47,9 @@ void main(void) {
// Choose the screen-space sample radius
float ssDiskRadius = evalDiskRadius(fragPositionES.z, imageSize);
#if SSAO_USE_HORIZON_BASED
ssDiskRadius = min(ssDiskRadius, SSAO_HBAO_MAX_RADIUS);
#endif
// Let's make noise
float randomPatternRotationAngle = getAngleDithering(centerPixelPos);

View file

@ -37,10 +37,10 @@ Rectangle {
"Level:obscuranceLevel:1.0:false",
"Num Taps:numSamples:32:true",
"Taps Spiral:numSpiralTurns:10.0:false",
"Falloff Bias:falloffBias:0.2:false",
"Silhouette Radius:silhouetteRadius:1.0:false",
"Falloff Angle:falloffAngle:0.2:false",
"Falloff Distance:falloffDistance:2.0:false",
"Blur Edge Sharpness:edgeSharpness:1.0:false",
"Blur Radius:blurRadius:10.0:false",
"Blur Radius:blurRadius:15.0:false",
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])