Two group of config settings for SSAO and HBAO

This commit is contained in:
Olivier Prat 2018-10-02 17:47:33 +02:00
parent 6fcd63ed64
commit dfe9deb154
6 changed files with 384 additions and 152 deletions

View file

@ -206,23 +206,87 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false), render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
radius{ 0.7f },
perspectiveScale{ 1.0f }, perspectiveScale{ 1.0f },
obscuranceLevel{ 0.15f },
falloffAngle{ 0.1f },
edgeSharpness{ 1.0f }, edgeSharpness{ 1.0f },
blurDeviation{ 2.5f },
numSpiralTurns{ 7.0f },
numSamples{ 1 },
resolutionLevel{ 2 }, resolutionLevel{ 2 },
blurRadius{ 4 }, blurRadius{ 4 },
ssaoRadius{ 1.0f },
ssaoObscuranceLevel{ 0.4f },
ssaoFalloffAngle{ 0.1f },
ssaoNumSamples{ 32 },
ssaoNumSpiralTurns{ 7.0f },
hbaoRadius{ 0.7f },
hbaoObscuranceLevel{ 0.75f },
hbaoFalloffAngle{ 0.3f },
hbaoNumSamples{ 1 },
ditheringEnabled{ true }, ditheringEnabled{ true },
borderingEnabled{ true }, borderingEnabled{ true },
fetchMipsEnabled{ true }, fetchMipsEnabled{ true },
horizonBased{ true }, horizonBased{ false },
jitterEnabled{ false }{ jitterEnabled{ false }{
} }
void AmbientOcclusionEffectConfig::setSSAORadius(float newRadius) {
ssaoRadius = std::max(0.01f, newRadius); emit dirty();
}
void AmbientOcclusionEffectConfig::setSSAOObscuranceLevel(float level) {
ssaoObscuranceLevel = std::max(0.01f, level);
emit dirty();
}
void AmbientOcclusionEffectConfig::setSSAOFalloffAngle(float bias) {
ssaoFalloffAngle = std::max(0.0f, std::min(bias, 1.0f));
emit dirty();
}
void AmbientOcclusionEffectConfig::setSSAONumSpiralTurns(float turns) {
ssaoNumSpiralTurns = std::max(0.0f, (float)turns);
emit dirty();
}
void AmbientOcclusionEffectConfig::setSSAONumSamples(int samples) {
ssaoNumSamples = std::max(1.0f, (float)samples);
emit dirty();
}
void AmbientOcclusionEffectConfig::setHBAORadius(float newRadius) {
hbaoRadius = std::max(0.01f, newRadius); emit dirty();
}
void AmbientOcclusionEffectConfig::setHBAOObscuranceLevel(float level) {
hbaoObscuranceLevel = std::max(0.01f, level);
emit dirty();
}
void AmbientOcclusionEffectConfig::setHBAOFalloffAngle(float bias) {
hbaoFalloffAngle = std::max(0.0f, std::min(bias, 1.0f));
emit dirty();
}
void AmbientOcclusionEffectConfig::setHBAONumSamples(int samples) {
hbaoNumSamples = std::max(1.0f, (float)samples);
emit dirty();
}
void AmbientOcclusionEffectConfig::setEdgeSharpness(float sharpness) {
edgeSharpness = std::max(0.0f, (float)sharpness);
emit dirty();
}
void AmbientOcclusionEffectConfig::setResolutionLevel(int level) {
resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL));
emit dirty();
}
void AmbientOcclusionEffectConfig::setBlurRadius(int radius) {
blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius));
emit dirty();
}
AmbientOcclusionEffect::AOParameters::AOParameters() { AmbientOcclusionEffect::AOParameters::AOParameters() {
_resolutionInfo = glm::vec4{ 0.0f }; _resolutionInfo = glm::vec4{ 0.0f };
_radiusInfo = glm::vec4{ 0.0f }; _radiusInfo = glm::vec4{ 0.0f };
@ -242,42 +306,17 @@ void AmbientOcclusionEffect::configure(const Config& config) {
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled); DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
bool shouldUpdateBlurs = false; bool shouldUpdateBlurs = false;
bool shouldUpdateTechnique = false;
_isJitterEnabled = config.jitterEnabled; _isJitterEnabled = config.jitterEnabled;
const double RADIUS_POWER = 6.0; if (!_framebuffer) {
const auto& radius = config.radius; _framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
if (radius != _aoParametersBuffer->getRadius() || config.horizonBased != _aoParametersBuffer->isHorizonBased()) { shouldUpdateBlurs = true;
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.x = radius;
current.y = radius * radius;
current.z = 10.0f;
if (!config.horizonBased) {
current.z *= (float)(1.0 / pow((double)radius, RADIUS_POWER));
}
}
if (config.horizonBased != _aoParametersBuffer->isHorizonBased()) {
auto& current = _aoParametersBuffer.edit()._resolutionInfo;
current.y = config.horizonBased & 1;
}
if (config.obscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) {
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.w = config.obscuranceLevel;
}
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 // Update bilateral blur
{ if (config.blurRadius != _hblurParametersBuffer->getBlurRadius() || _blurEdgeSharpness != config.edgeSharpness) {
const float BLUR_EDGE_DISTANCE_SCALE = float(10000 * SSAO_DEPTH_KEY_SCALE); const float BLUR_EDGE_DISTANCE_SCALE = float(10000 * SSAO_DEPTH_KEY_SCALE);
const float BLUR_EDGE_NORMAL_SCALE = 2.0f; const float BLUR_EDGE_NORMAL_SCALE = 2.0f;
@ -287,6 +326,8 @@ void AmbientOcclusionEffect::configure(const Config& config) {
float blurRadialScale = 1.0f / (2.0f*blurRadialSigma*blurRadialSigma); float blurRadialScale = 1.0f / (2.0f*blurRadialSigma*blurRadialSigma);
glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * config.edgeSharpness); glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * config.edgeSharpness);
_blurEdgeSharpness = config.edgeSharpness;
hblur.x = blurScales.x; hblur.x = blurScales.x;
hblur.y = blurScales.y; hblur.y = blurScales.y;
hblur.z = blurScales.z; hblur.z = blurScales.z;
@ -298,33 +339,10 @@ void AmbientOcclusionEffect::configure(const Config& config) {
vblur.w = (float)config.blurRadius; vblur.w = (float)config.blurRadius;
} }
if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { if (_aoParametersBuffer->isHorizonBased() != config.horizonBased) {
auto& current = _aoParametersBuffer.edit()._sampleInfo; auto& current = _aoParametersBuffer.edit()._resolutionInfo;
current.z = config.numSpiralTurns; current.y = config.horizonBased & 1;
} shouldUpdateTechnique = true;
if (config.numSamples != _aoParametersBuffer->getNumSamples()) {
auto& current = _aoParametersBuffer.edit()._sampleInfo;
current.x = config.numSamples;
current.y = 1.0f / config.numSamples;
// Regenerate offsets
const int B = 3;
const float invB = 1.0f / (float)B;
for (int i = 0; i < _randomSamples.size(); i++) {
int index = i+1; // Indices start at 1, not 0
float f = 1.0f;
float r = 0.0f;
while (index > 0) {
f = f * invB;
r = r + f * (float)(index % B);
index = index / B;
}
_randomSamples[i] = r * 2.0f * M_PI / config.numSamples;
}
updateJitterSamples();
} }
if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) {
@ -332,11 +350,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = (float)config.fetchMipsEnabled; current.w = (float)config.fetchMipsEnabled;
} }
if (!_framebuffer) {
_framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
shouldUpdateBlurs = true;
}
if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) {
_aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale; _aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale;
} }
@ -357,11 +370,102 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = (float)config.borderingEnabled; current.w = (float)config.borderingEnabled;
} }
if (config.horizonBased) {
// Configure for HBAO
const auto& radius = config.hbaoRadius;
if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) {
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.x = radius;
current.y = radius * radius;
current.z = 1.0f / current.y;
}
if (shouldUpdateTechnique || config.hbaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) {
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.w = config.hbaoObscuranceLevel;
}
if (shouldUpdateTechnique || config.hbaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) {
auto& current = _aoParametersBuffer.edit()._falloffInfo;
current.x = config.hbaoFalloffAngle;
current.y = 1.0f / (1.0f - current.x);
// Compute sin from cos
current.z = sqrtf(1.0f - config.hbaoFalloffAngle * config.hbaoFalloffAngle);
current.w = 1.0f / current.z;
}
if (shouldUpdateTechnique || config.hbaoNumSamples != _aoParametersBuffer->getNumSamples()) {
auto& current = _aoParametersBuffer.edit()._sampleInfo;
current.x = config.hbaoNumSamples;
current.y = 1.0f / config.hbaoNumSamples;
updateRandomSamples();
updateJitterSamples();
}
} else {
// Configure for SSAO
const double RADIUS_POWER = 6.0;
const auto& radius = config.ssaoRadius;
if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) {
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.x = radius;
current.y = radius * radius;
current.z = (float)(10.0 / pow((double)radius, RADIUS_POWER));
}
if (shouldUpdateTechnique || config.ssaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) {
auto& current = _aoParametersBuffer.edit()._radiusInfo;
current.w = config.ssaoObscuranceLevel;
}
if (shouldUpdateTechnique || config.ssaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) {
auto& current = _aoParametersBuffer.edit()._falloffInfo;
current.x = config.ssaoFalloffAngle;
}
if (shouldUpdateTechnique || config.ssaoNumSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) {
auto& current = _aoParametersBuffer.edit()._sampleInfo;
current.z = config.ssaoNumSpiralTurns;
}
if (shouldUpdateTechnique || config.ssaoNumSamples != _aoParametersBuffer->getNumSamples()) {
auto& current = _aoParametersBuffer.edit()._sampleInfo;
current.x = config.ssaoNumSamples;
current.y = 1.0f / config.ssaoNumSamples;
updateRandomSamples();
updateJitterSamples();
}
}
if (shouldUpdateBlurs) { if (shouldUpdateBlurs) {
updateBlurParameters(); updateBlurParameters();
} }
} }
void AmbientOcclusionEffect::updateRandomSamples() {
// Regenerate offsets
if (_aoParametersBuffer->isHorizonBased()) {
const int B = 3;
const float invB = 1.0f / (float)B;
float sampleScale = 2.0f * M_PI / _aoParametersBuffer->getNumSamples();
for (int i = 0; i < _randomSamples.size(); i++) {
int index = i + 1; // Indices start at 1, not 0
float f = 1.0f;
float r = 0.0f;
while (index > 0) {
f = f * invB;
r = r + f * (float)(index % B);
index = index / B;
}
_randomSamples[i] = r * sampleScale;
}
} else {
for (int i = 0; i < _randomSamples.size(); i++) {
_randomSamples[i] = randFloat() * 2.0f * M_PI;
}
}
}
void AmbientOcclusionEffect::updateBlurParameters() { void AmbientOcclusionEffect::updateBlurParameters() {
const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel(); const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel();
auto& vblur = _vblurParametersBuffer.edit(); auto& vblur = _vblurParametersBuffer.edit();
@ -477,9 +581,14 @@ int AmbientOcclusionEffect::getDepthResolutionLevel() const {
} }
void AmbientOcclusionEffect::updateJitterSamples() { void AmbientOcclusionEffect::updateJitterSamples() {
for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) { if (_aoParametersBuffer->isHorizonBased()) {
auto& sample = _aoFrameParametersBuffer[splitId].edit(); for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) {
sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId]; auto& sample = _aoFrameParametersBuffer[splitId].edit();
sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId];
}
} else {
auto& sample = _aoFrameParametersBuffer[0].edit();
sample._angleInfo.x = _randomSamples[_frameId];
} }
} }
@ -594,57 +703,69 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte
batch.setPipeline(occlusionPipeline); batch.setPipeline(occlusionPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture);
if (_aoParametersBuffer->isHorizonBased()) {
#if SSAO_USE_QUAD_SPLIT #if SSAO_USE_QUAD_SPLIT
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture); batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture);
{ {
const auto uvScale = glm::vec3( const auto uvScale = glm::vec3(
(splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z), (splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z),
(splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w), (splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w),
1.0f); 1.0f);
const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionViewport.z, occlusionViewport.w); const auto postPixelOffset = glm::vec2(0.5f) / glm::vec2(occlusionViewport.z, occlusionViewport.w);
const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize); const auto prePixelOffset = glm::vec2(0.5f * uvScale.x, 0.5f * uvScale.y) / glm::vec2(splitSize);
Transform model; Transform model;
batch.setViewportTransform(splitViewport); batch.setViewportTransform(splitViewport);
model.setScale(uvScale); model.setScale(uvScale);
for (int y = 0; y < SSAO_SPLIT_COUNT; y++) { for (int y = 0; y < SSAO_SPLIT_COUNT; y++) {
for (int x = 0; x < SSAO_SPLIT_COUNT; x++) { for (int x = 0; x < SSAO_SPLIT_COUNT; x++) {
const int splitIndex = x + y * SSAO_SPLIT_COUNT; const int splitIndex = x + y * SSAO_SPLIT_COUNT;
const auto uvTranslate = glm::vec3( const auto uvTranslate = glm::vec3(
postPixelOffset.x * (2 * x + 1) - prePixelOffset.x, postPixelOffset.x * (2 * x + 1) - prePixelOffset.x,
postPixelOffset.y * (2 * y + 1) - prePixelOffset.y, postPixelOffset.y * (2 * y + 1) - prePixelOffset.y,
0.0f 0.0f
); );
model.setTranslation(uvTranslate); model.setTranslation(uvTranslate);
batch.setModelTransform(model); batch.setModelTransform(model);
batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex)); batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex));
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
}
} }
} }
}
#else #else
batch.setViewportTransform(occlusionViewport); batch.setViewportTransform(occlusionViewport);
model.setIdentity(); batch.setModelTransform(Transform());
batch.setModelTransform(model); batch.setFramebuffer(occlusionFBO);
batch.setFramebuffer(occlusionFBO); batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]);
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]); batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.draw(gpu::TRIANGLE_STRIP, 4);
#endif #endif
} else {
#if SSAO_USE_QUAD_SPLIT
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture);
#endif
batch.setViewportTransform(occlusionViewport);
batch.setModelTransform(Transform());
batch.setFramebuffer(occlusionFBO);
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
batch.popProfileRange(); batch.popProfileRange();
#if SSAO_USE_QUAD_SPLIT #if SSAO_USE_QUAD_SPLIT
// Gather back the four separate renders into one interleaved one if (_aoParametersBuffer->isHorizonBased()) {
batch.pushProfileRange("Gather"); // Gather back the four separate renders into one interleaved one
batch.setViewportTransform(occlusionViewport); batch.pushProfileRange("Gather");
batch.setModelTransform(Transform()); batch.setViewportTransform(occlusionViewport);
batch.setFramebuffer(occlusionFBO); batch.setModelTransform(Transform());
batch.setPipeline(gatherPipeline); batch.setFramebuffer(occlusionFBO);
batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture()); batch.setPipeline(gatherPipeline);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture());
batch.popProfileRange(); batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.popProfileRange();
}
#endif #endif
{ {

View file

@ -84,42 +84,61 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty) Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty)
Q_PROPERTY(bool jitterEnabled MEMBER jitterEnabled NOTIFY dirty) Q_PROPERTY(bool jitterEnabled MEMBER jitterEnabled NOTIFY dirty)
Q_PROPERTY(float radius MEMBER radius WRITE setRadius)
Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel)
Q_PROPERTY(float falloffAngle MEMBER falloffAngle WRITE setFalloffAngle)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
Q_PROPERTY(float blurDeviation MEMBER blurDeviation WRITE setBlurDeviation)
Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns WRITE setNumSpiralTurns)
Q_PROPERTY(int numSamples MEMBER numSamples WRITE setNumSamples)
Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel) Q_PROPERTY(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius) Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
// SSAO
Q_PROPERTY(float ssaoRadius MEMBER ssaoRadius WRITE setSSAORadius)
Q_PROPERTY(float ssaoObscuranceLevel MEMBER ssaoObscuranceLevel WRITE setSSAOObscuranceLevel)
Q_PROPERTY(float ssaoFalloffAngle MEMBER ssaoFalloffAngle WRITE setSSAOFalloffAngle)
Q_PROPERTY(float ssaoNumSpiralTurns MEMBER ssaoNumSpiralTurns WRITE setSSAONumSpiralTurns)
Q_PROPERTY(int ssaoNumSamples MEMBER ssaoNumSamples WRITE setSSAONumSamples)
// HBAO
Q_PROPERTY(float hbaoRadius MEMBER hbaoRadius WRITE setHBAORadius)
Q_PROPERTY(float hbaoObscuranceLevel MEMBER hbaoObscuranceLevel WRITE setHBAOObscuranceLevel)
Q_PROPERTY(float hbaoFalloffAngle MEMBER hbaoFalloffAngle WRITE setHBAOFalloffAngle)
Q_PROPERTY(int hbaoNumSamples MEMBER hbaoNumSamples WRITE setHBAONumSamples)
public: public:
AmbientOcclusionEffectConfig(); AmbientOcclusionEffectConfig();
const int MAX_RESOLUTION_LEVEL = 4; const int MAX_RESOLUTION_LEVEL = 4;
const int MAX_BLUR_RADIUS = 15; const int MAX_BLUR_RADIUS = 15;
void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); } void setEdgeSharpness(float sharpness);
void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); } void setResolutionLevel(int level);
void setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 1.0f)); emit dirty(); } void setBlurRadius(int radius);
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 setSSAORadius(float newRadius);
void setNumSpiralTurns(float turns) { numSpiralTurns = std::max(0.0f, (float)turns); emit dirty(); } void setSSAOObscuranceLevel(float level);
void setNumSamples(int samples) { numSamples = std::max(1.0f, (float)samples); emit dirty(); } void setSSAOFalloffAngle(float bias);
void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); } void setSSAONumSpiralTurns(float turns);
void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); } void setSSAONumSamples(int samples);
void setHBAORadius(float newRadius);
void setHBAOObscuranceLevel(float level);
void setHBAOFalloffAngle(float bias);
void setHBAONumSamples(int samples);
float radius;
float perspectiveScale; float perspectiveScale;
float obscuranceLevel; // intensify or dim down the obscurance effect
float falloffAngle;
float edgeSharpness; float edgeSharpness;
float blurDeviation;
float numSpiralTurns; // defining an angle span to distribute the samples ray directions
int numSamples;
int resolutionLevel;
int blurRadius; // 0 means no blurring int blurRadius; // 0 means no blurring
int resolutionLevel;
float ssaoRadius;
float ssaoObscuranceLevel; // intensify or dim down the obscurance effect
float ssaoFalloffAngle;
float ssaoNumSpiralTurns; // defining an angle span to distribute the samples ray directions
int ssaoNumSamples;
float hbaoRadius;
float hbaoObscuranceLevel; // intensify or dim down the obscurance effect
float hbaoFalloffAngle;
int hbaoNumSamples;
bool horizonBased; // Use horizon based AO bool horizonBased; // Use horizon based AO
bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true
bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true
@ -154,7 +173,7 @@ public:
float getRadius() const { return _radiusInfo.x; } float getRadius() const { return _radiusInfo.x; }
float getPerspectiveScale() const { return _resolutionInfo.z; } float getPerspectiveScale() const { return _resolutionInfo.z; }
float getObscuranceLevel() const { return _radiusInfo.w; } float getObscuranceLevel() const { return _radiusInfo.w; }
float getFalloffCosAngle() const { return (float)_falloffInfo.x; } float getFalloffAngle() const { return (float)_falloffInfo.x; }
float getNumSpiralTurns() const { return _sampleInfo.z; } float getNumSpiralTurns() const { return _sampleInfo.z; }
int getNumSamples() const { return (int)_sampleInfo.x; } int getNumSamples() const { return (int)_sampleInfo.x; }
@ -176,7 +195,7 @@ private:
BlurParameters(); BlurParameters();
float getEdgeSharpness() const { return (float)_blurInfo.x; } float getEdgeSharpness() const { return (float)_blurInfo.x; }
int getBlurRadius() const { return (int)_blurInfo.y; } int getBlurRadius() const { return (int)_blurInfo.w; }
}; };
using BlurParametersBuffer = gpu::StructBuffer<BlurParameters>; using BlurParametersBuffer = gpu::StructBuffer<BlurParameters>;
@ -185,6 +204,7 @@ private:
void updateBlurParameters(); void updateBlurParameters();
void updateFramebufferSizes(); void updateFramebufferSizes();
void updateRandomSamples();
void updateJitterSamples(); void updateJitterSamples();
int getDepthResolutionLevel() const; int getDepthResolutionLevel() const;
@ -193,6 +213,7 @@ private:
FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT];
BlurParametersBuffer _vblurParametersBuffer; BlurParametersBuffer _vblurParametersBuffer;
BlurParametersBuffer _hblurParametersBuffer; BlurParametersBuffer _hblurParametersBuffer;
float _blurEdgeSharpness{ 0.0f };
static const gpu::PipelinePointer& getOcclusionPipeline(); static const gpu::PipelinePointer& getOcclusionPipeline();
static const gpu::PipelinePointer& getBilateralBlurPipeline(); static const gpu::PipelinePointer& getBilateralBlurPipeline();

View file

@ -86,7 +86,7 @@ void LinearDepthFramebuffer::allocate() {
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5; const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
// Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO // Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO
const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP); const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP);
_halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL, _halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::HALF, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL,
depthSamplerHalf); depthSamplerHalf);
_halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP, _halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP,

View file

@ -107,11 +107,14 @@ float getRadius2() {
return params._radiusInfo.y; return params._radiusInfo.y;
} }
float getInvRadius6() { float getInvRadius6() {
return mix(params._radiusInfo.z, 1.0, isHorizonBased());
}
float getInvRadius2() {
return params._radiusInfo.z; return params._radiusInfo.z;
} }
float getObscuranceScaling() { float getObscuranceScaling() {
return params._radiusInfo.z * params._radiusInfo.w; return getInvRadius6() * params._radiusInfo.w;
} }
float isDitheringEnabled() { float isDitheringEnabled() {
@ -161,15 +164,24 @@ float getAngleDitheringWorldPos(in vec3 pixelWorldPos) {
return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10); return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10);
} }
float getAngleDitheringSplit() {
return isDitheringEnabled() * frameParams._angleInfo.x;
}
float getAngleDithering(in ivec2 pixelPos) { float getAngleDithering(in ivec2 pixelPos) {
#if SSAO_USE_QUAD_SPLIT #if SSAO_USE_QUAD_SPLIT
return isDitheringEnabled() * frameParams._angleInfo.x; return getAngleDitheringSplit();
#else #else
// Hash function used in the AlchemyAO paper // Hash function used in the AlchemyAO paper
return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10); return getAngleDitheringPixelPos(pixelPos);
#endif #endif
} }
float getAngleDitheringPixelPos(in ivec2 pixelPos) {
// Hash function used in the AlchemyAO paper
return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10);
}
float evalDiskRadius(float Zeye, vec2 sideImageSize) { float evalDiskRadius(float Zeye, vec2 sideImageSize) {
// Choose the screen-space sample radius // Choose the screen-space sample radius
// proportional to the projected area of the sphere // proportional to the projected area of the sphere
@ -413,7 +425,7 @@ float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 t
#define HBAO_USE_OVERHANG_HACK 0 #define HBAO_USE_OVERHANG_HACK 0
float computeWeightForHorizon(float horizonLimit, float distanceSquared) { float computeWeightForHorizon(float horizonLimit, float distanceSquared) {
return max(0.0, 1.0 - distanceSquared / getRadius2()); return max(0.0, 1.0 - distanceSquared * getInvRadius2());
} }
float computeWeightedHorizon(float horizonLimit, float distanceSquared) { float computeWeightedHorizon(float horizonLimit, float distanceSquared) {

View file

@ -37,13 +37,18 @@ void main(void) {
// Stereo side info based on the real viewport size of this pass // Stereo side info based on the real viewport size of this pass
vec2 sideDepthSize = getDepthTextureSideSize(0); vec2 sideDepthSize = getDepthTextureSideSize(0);
ivec2 sideOcclusionSize = ivec2( getOcclusionSplitSideSize() ); ivec2 sideOcclusionSize;
if (isHorizonBased()) {
sideOcclusionSize = ivec2( getOcclusionSplitSideSize() );
} else {
sideOcclusionSize = ivec2( getOcclusionSideSize() );
}
ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x); ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x);
// From now on, fragUVPos is the UV pos in the side // From now on, fragUVPos is the UV pos in the side
fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo()); fragUVPos.x = mix(fragUVPos.x, fragUVPos.x * 2.0 - getStereoSide(side), isStereo());
fragUVPos = snapToTexel(fragUVPos, sideDepthSize); fragUVPos = snapToTexel(fragUVPos, sideDepthSize);
// The position and normal of the pixel fragment in Eye space // The position and normal of the pixel fragment in Eye space
vec2 deltaDepthUV = vec2(2.0) / sideDepthSize; vec2 deltaDepthUV = vec2(2.0) / sideDepthSize;
vec3 fragPositionES = buildPosition(side, fragUVPos); vec3 fragPositionES = buildPosition(side, fragUVPos);
@ -58,7 +63,7 @@ void main(void) {
} }
// Let's make noise // Let's make noise
float randomPatternRotationAngle = getAngleDithering(fragPixelPos); float randomPatternRotationAngle = 0.0;
// Accumulate the obscurance for each samples // Accumulate the obscurance for each samples
float obscuranceSum = 0.0; float obscuranceSum = 0.0;
@ -66,22 +71,24 @@ void main(void) {
float invNumSamples = getInvNumSamples(); float invNumSamples = getInvNumSamples();
if (isHorizonBased()) { if (isHorizonBased()) {
randomPatternRotationAngle = getAngleDithering(fragPixelPos);
for (int i = 0; i < numSamples; ++i) { for (int i = 0; i < numSamples; ++i) {
vec3 deltaTap = getUnitTapLocation(i, 1.0, randomPatternRotationAngle, PI); 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, fragNormalES);
} }
obscuranceSum *= invNumSamples; obscuranceSum *= invNumSamples;
#if HBAO_USE_COS_ANGLE #if HBAO_USE_COS_ANGLE
obscuranceSum *= 0.5;
obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling(); obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling();
#else #else
obscuranceSum *= 0.5;
obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling()); obscuranceSum = mix(1.0, obscuranceSum, getObscuranceScaling());
#endif #endif
} else { } else {
// Steps are in the depth texture resolution // Steps are in the depth texture resolution
vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize; vec2 depthTexFragPixelPos = fragUVPos * sideDepthSize;
randomPatternRotationAngle = getAngleDitheringPixelPos(fragPixelPos) + getAngleDitheringSplit();
for (int i = 0; i < numSamples; ++i) { for (int i = 0; i < numSamples; ++i) {
vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize); vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, diskPixelRadius, depthTexFragPixelPos, sideDepthSize);
vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV; vec2 tapUV = fragUVPos + tap.xy * deltaDepthUV;
@ -90,7 +97,7 @@ void main(void) {
obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES); obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES);
} }
obscuranceSum *= invNumSamples; obscuranceSum *= invNumSamples;
obscuranceSum = 1.0 - obscuranceSum * obscuranceSum * getObscuranceScaling(); obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling();
} }
float occlusion = clamp(obscuranceSum, 0.0, 1.0); float occlusion = clamp(obscuranceSum, 0.0, 1.0);

View file

@ -33,11 +33,6 @@ Rectangle {
Repeater { Repeater {
model: [ model: [
"Radius:radius:2.0:false",
"Level:obscuranceLevel:1.0:false",
"Num Taps:numSamples:16:true",
"Taps Spiral:numSpiralTurns:10.0:false",
"Falloff Angle:falloffAngle:1.0:false",
"Blur Edge Sharpness:edgeSharpness:1.0:false", "Blur Edge Sharpness:edgeSharpness:1.0:false",
"Blur Radius:blurRadius:15.0:true", "Blur Radius:blurRadius:15.0:true",
"Resolution Downscale:resolutionLevel:2:true", "Resolution Downscale:resolutionLevel:2:true",
@ -102,5 +97,81 @@ Rectangle {
} }
] ]
} }
TabView {
anchors.left: parent.left
anchors.right: parent.right
height: 400
Tab {
title: "SSAO"
Rectangle {
color: hifi.colors.baseGray;
Column {
spacing: 8
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: hifi.dimensions.contentMargin.x
Repeater {
model: [
"Radius:ssaoRadius:2.0:false",
"Level:ssaoObscuranceLevel:1.0:false",
"Num Taps:ssaoNumSamples:64:true",
"Taps Spiral:ssaoNumSpiralTurns:10.0:false",
"Falloff Angle:ssaoFalloffAngle:1.0:false",
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: (modelData.split(":")[3] == 'true')
config: Render.getConfig("RenderMainView.AmbientOcclusion")
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: 0.0
height:38
}
}
}
}
}
Tab {
title: "HBAO"
Rectangle {
color: hifi.colors.baseGray;
Column {
spacing: 8
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: hifi.dimensions.contentMargin.x
Repeater {
model: [
"Radius:hbaoRadius:2.0:false",
"Level:hbaoObscuranceLevel:1.0:false",
"Num Taps:hbaoNumSamples:6:true",
"Falloff Angle:hbaoFalloffAngle:1.0:false",
]
ConfigSlider {
label: qsTr(modelData.split(":")[0])
integral: (modelData.split(":")[3] == 'true')
config: Render.getConfig("RenderMainView.AmbientOcclusion")
property: modelData.split(":")[1]
max: modelData.split(":")[2]
min: 0.0
height:38
}
}
}
}
}
}
} }
} }