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() :
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
radius{ 0.7f },
perspectiveScale{ 1.0f },
obscuranceLevel{ 0.15f },
falloffAngle{ 0.1f },
edgeSharpness{ 1.0f },
blurDeviation{ 2.5f },
numSpiralTurns{ 7.0f },
numSamples{ 1 },
resolutionLevel{ 2 },
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 },
borderingEnabled{ true },
fetchMipsEnabled{ true },
horizonBased{ true },
horizonBased{ 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() {
_resolutionInfo = 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);
bool shouldUpdateBlurs = false;
bool shouldUpdateTechnique = false;
_isJitterEnabled = config.jitterEnabled;
const double RADIUS_POWER = 6.0;
const auto& radius = config.radius;
if (radius != _aoParametersBuffer->getRadius() || config.horizonBased != _aoParametersBuffer->isHorizonBased()) {
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;
if (!_framebuffer) {
_framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
shouldUpdateBlurs = true;
}
// 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_NORMAL_SCALE = 2.0f;
@ -287,6 +326,8 @@ void AmbientOcclusionEffect::configure(const Config& config) {
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);
_blurEdgeSharpness = config.edgeSharpness;
hblur.x = blurScales.x;
hblur.y = blurScales.y;
hblur.z = blurScales.z;
@ -298,33 +339,10 @@ void AmbientOcclusionEffect::configure(const Config& config) {
vblur.w = (float)config.blurRadius;
}
if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) {
auto& current = _aoParametersBuffer.edit()._sampleInfo;
current.z = config.numSpiralTurns;
}
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 (_aoParametersBuffer->isHorizonBased() != config.horizonBased) {
auto& current = _aoParametersBuffer.edit()._resolutionInfo;
current.y = config.horizonBased & 1;
shouldUpdateTechnique = true;
}
if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) {
@ -332,11 +350,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = (float)config.fetchMipsEnabled;
}
if (!_framebuffer) {
_framebuffer = std::make_shared<AmbientOcclusionFramebuffer>();
shouldUpdateBlurs = true;
}
if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) {
_aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale;
}
@ -357,11 +370,102 @@ void AmbientOcclusionEffect::configure(const Config& config) {
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) {
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() {
const auto resolutionLevel = _aoParametersBuffer->getResolutionLevel();
auto& vblur = _vblurParametersBuffer.edit();
@ -477,9 +581,14 @@ int AmbientOcclusionEffect::getDepthResolutionLevel() const {
}
void AmbientOcclusionEffect::updateJitterSamples() {
for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) {
auto& sample = _aoFrameParametersBuffer[splitId].edit();
sample._angleInfo.x = _randomSamples[splitId + SSAO_RANDOM_SAMPLE_COUNT * _frameId];
if (_aoParametersBuffer->isHorizonBased()) {
for (int splitId = 0; splitId < SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT; splitId++) {
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.setResourceTexture(render_utils::slot::texture::SsaoDepth, occlusionDepthTexture);
if (_aoParametersBuffer->isHorizonBased()) {
#if SSAO_USE_QUAD_SPLIT
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture);
{
const auto uvScale = glm::vec3(
(splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z),
(splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w),
1.0f);
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);
Transform model;
batch.setResourceTexture(render_utils::slot::texture::SsaoNormal, occlusionNormalTexture);
{
const auto uvScale = glm::vec3(
(splitSize.x * SSAO_SPLIT_COUNT) / float(occlusionViewport.z),
(splitSize.y * SSAO_SPLIT_COUNT) / float(occlusionViewport.w),
1.0f);
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);
Transform model;
batch.setViewportTransform(splitViewport);
batch.setViewportTransform(splitViewport);
model.setScale(uvScale);
for (int y = 0; y < SSAO_SPLIT_COUNT; y++) {
for (int x = 0; x < SSAO_SPLIT_COUNT; x++) {
const int splitIndex = x + y * SSAO_SPLIT_COUNT;
const auto uvTranslate = glm::vec3(
postPixelOffset.x * (2 * x + 1) - prePixelOffset.x,
postPixelOffset.y * (2 * y + 1) - prePixelOffset.y,
0.0f
model.setScale(uvScale);
for (int y = 0; y < SSAO_SPLIT_COUNT; y++) {
for (int x = 0; x < SSAO_SPLIT_COUNT; x++) {
const int splitIndex = x + y * SSAO_SPLIT_COUNT;
const auto uvTranslate = glm::vec3(
postPixelOffset.x * (2 * x + 1) - prePixelOffset.x,
postPixelOffset.y * (2 * y + 1) - prePixelOffset.y,
0.0f
);
model.setTranslation(uvTranslate);
batch.setModelTransform(model);
batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex));
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
model.setTranslation(uvTranslate);
batch.setModelTransform(model);
batch.setFramebuffer(_framebuffer->getOcclusionSplitFramebuffer(splitIndex));
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[splitIndex]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
}
}
}
#else
batch.setViewportTransform(occlusionViewport);
model.setIdentity();
batch.setModelTransform(model);
batch.setFramebuffer(occlusionFBO);
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.setViewportTransform(occlusionViewport);
batch.setModelTransform(Transform());
batch.setFramebuffer(occlusionFBO);
batch.setUniformBuffer(render_utils::slot::buffer::SsaoFrameParams, _aoFrameParametersBuffer[0]);
batch.draw(gpu::TRIANGLE_STRIP, 4);
#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();
#if SSAO_USE_QUAD_SPLIT
// Gather back the four separate renders into one interleaved one
batch.pushProfileRange("Gather");
batch.setViewportTransform(occlusionViewport);
batch.setModelTransform(Transform());
batch.setFramebuffer(occlusionFBO);
batch.setPipeline(gatherPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture());
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.popProfileRange();
if (_aoParametersBuffer->isHorizonBased()) {
// Gather back the four separate renders into one interleaved one
batch.pushProfileRange("Gather");
batch.setViewportTransform(occlusionViewport);
batch.setModelTransform(Transform());
batch.setFramebuffer(occlusionFBO);
batch.setPipeline(gatherPipeline);
batch.setResourceTexture(render_utils::slot::texture::SsaoOcclusion, _framebuffer->getOcclusionSplitTexture());
batch.draw(gpu::TRIANGLE_STRIP, 4);
batch.popProfileRange();
}
#endif
{

View file

@ -84,42 +84,61 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled 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(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
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:
AmbientOcclusionEffectConfig();
const int MAX_RESOLUTION_LEVEL = 4;
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 setFalloffAngle(float bias) { falloffAngle = std::max(0.0f, std::min(bias, 1.0f)); 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(); }
void setNumSamples(int samples) { numSamples = std::max(1.0f, (float)samples); emit dirty(); }
void setResolutionLevel(int level) { resolutionLevel = std::max(0, std::min(level, MAX_RESOLUTION_LEVEL)); emit dirty(); }
void setBlurRadius(int radius) { blurRadius = std::max(0, std::min(MAX_BLUR_RADIUS, radius)); emit dirty(); }
void setEdgeSharpness(float sharpness);
void setResolutionLevel(int level);
void setBlurRadius(int radius);
void setSSAORadius(float newRadius);
void setSSAOObscuranceLevel(float level);
void setSSAOFalloffAngle(float bias);
void setSSAONumSpiralTurns(float turns);
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 obscuranceLevel; // intensify or dim down the obscurance effect
float falloffAngle;
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 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 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
@ -154,7 +173,7 @@ public:
float getRadius() const { return _radiusInfo.x; }
float getPerspectiveScale() const { return _resolutionInfo.z; }
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; }
int getNumSamples() const { return (int)_sampleInfo.x; }
@ -176,7 +195,7 @@ private:
BlurParameters();
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>;
@ -185,6 +204,7 @@ private:
void updateBlurParameters();
void updateFramebufferSizes();
void updateRandomSamples();
void updateJitterSamples();
int getDepthResolutionLevel() const;
@ -193,6 +213,7 @@ private:
FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT];
BlurParametersBuffer _vblurParametersBuffer;
BlurParametersBuffer _hblurParametersBuffer;
float _blurEdgeSharpness{ 0.0f };
static const gpu::PipelinePointer& getOcclusionPipeline();
static const gpu::PipelinePointer& getBilateralBlurPipeline();

View file

@ -86,7 +86,7 @@ void LinearDepthFramebuffer::allocate() {
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
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);
_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;
}
float getInvRadius6() {
return mix(params._radiusInfo.z, 1.0, isHorizonBased());
}
float getInvRadius2() {
return params._radiusInfo.z;
}
float getObscuranceScaling() {
return params._radiusInfo.z * params._radiusInfo.w;
return getInvRadius6() * params._radiusInfo.w;
}
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);
}
float getAngleDitheringSplit() {
return isDitheringEnabled() * frameParams._angleInfo.x;
}
float getAngleDithering(in ivec2 pixelPos) {
#if SSAO_USE_QUAD_SPLIT
return isDitheringEnabled() * frameParams._angleInfo.x;
return getAngleDitheringSplit();
#else
// Hash function used in the AlchemyAO paper
return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10);
return getAngleDitheringPixelPos(pixelPos);
#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) {
// Choose the screen-space sample radius
// 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
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) {

View file

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

View file

@ -33,11 +33,6 @@ Rectangle {
Repeater {
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 Radius:blurRadius:15.0: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
}
}
}
}
}
}
}
}