Exposing many more controls of the AO in order to adjust the effect

This commit is contained in:
samcake 2016-01-13 18:57:47 -08:00
parent 89d2d102f6
commit 0285d48de3
8 changed files with 108 additions and 21 deletions

View file

@ -109,6 +109,21 @@ panel.newSlider("Ambient Occlusion Level", 0.0, 1.0,
function() { return Render.ambientOcclusion.level; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Num Samples", 1, 32,
function (value) { Render.ambientOcclusion.numSamples = value; },
function() { return Render.ambientOcclusion.numSamples; },
function (value) { return (value); });
panel.newSlider("Ambient Occlusion Num Spiral Turns", 0.0, 30.0,
function (value) { Render.ambientOcclusion.numSpiralTurns = value; },
function() { return Render.ambientOcclusion.numSpiralTurns; },
function (value) { return (value); });
panel.newCheckbox("Ambient Occlusion Dithering",
function (value) { Render.ambientOcclusion.ditheringEnabled = value; },
function() { return Render.ambientOcclusion.ditheringEnabled; },
function (value) { return (value); });
var tickTackPeriod = 500;
function updateCounters() {

View file

@ -177,11 +177,35 @@ void AmbientOcclusionEffect::setLevel(float level) {
}
}
void AmbientOcclusionEffect::setDithering(bool enabled) {
if (enabled != isDitheringEnabled()) {
auto& current = _parametersBuffer.edit<Parameters>()._performanceCaps;
current.x = (float)enabled;
auto& current = _parametersBuffer.edit<Parameters>()._sampleInfo;
current.w = (float)enabled;
}
}
void AmbientOcclusionEffect::setNumSamples(int numSamples) {
numSamples = std::max(1.f, (float) numSamples);
if (numSamples != getNumSamples()) {
auto& current = _parametersBuffer.edit<Parameters>()._sampleInfo;
current.x = numSamples;
current.y = 1.0 / numSamples;
}
}
void AmbientOcclusionEffect::setNumSpiralTurns(float numTurns) {
numTurns = std::max(0.f, (float)numTurns);
if (numTurns != getNumSpiralTurns()) {
auto& current = _parametersBuffer.edit<Parameters>()._sampleInfo;
current.z = numTurns;
}
}
void AmbientOcclusionEffect::setEdgeSharpness(float sharpness) {
sharpness = std::max(0.f, (float)sharpness);
if (sharpness != getEdgeSharpness()) {
auto& current = _parametersBuffer.edit<Parameters>()._blurInfo;
current.x = sharpness;
}
}
@ -314,6 +338,8 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip());
_parametersBuffer.edit<Parameters>()._projection[0] = monoProjMat;
_parametersBuffer.edit<Parameters>()._pixelInfo = args->_viewport;
_parametersBuffer.edit<Parameters>()._ditheringInfo.y += 0.25f;
auto pyramidPipeline = getPyramidPipeline();
auto occlusionPipeline = getOcclusionPipeline();

View file

@ -31,8 +31,19 @@ public:
float getLevel() const { return _parametersBuffer.get<Parameters>()._radiusInfo.w; }
void setDithering(bool enabled);
bool isDitheringEnabled() const { return _parametersBuffer.get<Parameters>()._performanceCaps.x; }
bool isDitheringEnabled() const { return _parametersBuffer.get<Parameters>()._ditheringInfo.w; }
// Number of samples per pixel to evaluate the Obscurance
void setNumSamples(int numSamples);
int getNumSamples() const { return (int)_parametersBuffer.get<Parameters>()._sampleInfo.x; }
// Number of spiral turns defining an angle span to distribute the samples ray directions
void setNumSpiralTurns(float numTurns);
float getNumSpiralTurns() const { return _parametersBuffer.get<Parameters>()._sampleInfo.z; }
// Edge blurring setting
void setEdgeSharpness(float sharpness);
int getEdgeSharpness() const { return (int)_parametersBuffer.get<Parameters>()._blurInfo.x; }
using JobModel = render::Task::Job::Model<AmbientOcclusionEffect>;
@ -45,8 +56,12 @@ private:
public:
// radius info is { R, R^2, 1 / R^6, ObscuranceScale}
glm::vec4 _radiusInfo{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 1.0 };
// Performance parameters to adjust the effect
glm::vec4 _performanceCaps{ 1.0, 1.0, 1.0, 1.0 };
// Dithering info
glm::vec4 _ditheringInfo{ 1.0, 0.0, 0.0, 0.0 };
// Sampling info
glm::vec4 _sampleInfo{ 11.0, 1.0/11.0, 7.0, 1.0 };
// Blurring info
glm::vec4 _blurInfo{ 1.0, 0.0, 0.0, 0.0 };
// Pixel info is { viemport width height and stereo on off}
glm::vec4 _pixelInfo;
// Depth info is { n.f, f - n, -f}

View file

@ -183,7 +183,10 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
if (_occlusionJobIndex >= 0) {
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setRadius(renderContext->getAmbientOcclusion().radius);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setLevel(renderContext->getAmbientOcclusion().level);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setNumSamples(renderContext->getAmbientOcclusion().numSamples);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setNumSpiralTurns(renderContext->getAmbientOcclusion().numSpiralTurns);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled);
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness);
}
setAntialiasingStatus(renderContext->getFxaaStatus());

View file

@ -72,7 +72,10 @@ namespace RenderScripting {
public:
Q_PROPERTY(float radius MEMBER radius)
Q_PROPERTY(float level MEMBER level)
Q_PROPERTY(int numSamples MEMBER numSamples)
Q_PROPERTY(float numSpiralTurns MEMBER numSpiralTurns)
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled)
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness)
};
using AmbientOcclusionPointer = std::unique_ptr<AmbientOcclusion>;
};

View file

@ -33,7 +33,9 @@ vec2 unpackOcclusionDepth(vec3 raw) {
struct AmbientOcclusionParams {
vec4 _radiusInfo;
vec4 _performanceCaps;
vec4 _ditheringInfo;
vec4 _sampleInfo;
vec4 _blurInfo;
vec4 _pixelInfo;
vec4 _depthInfo;
mat4 _projection[2];
@ -67,7 +69,25 @@ float getObscuranceScaling() {
}
float isDitheringEnabled() {
return params._performanceCaps.x;
return params._ditheringInfo.x;
}
float getFrameDithering() {
return params._ditheringInfo.y;
}
float getNumSamples() {
return params._sampleInfo.x;
}
float getInvNumSamples() {
return params._sampleInfo.y;
}
float getNumSpiralTurns() {
return params._sampleInfo.z;
}
float getBlurEdgeSharpness() {
return params._blurInfo.x;
}
float evalZeyeFromZdb(float depth) {
@ -92,6 +112,7 @@ vec3 evalEyeNormal(vec3 C) {
<@func declareBlurPass(axis)@>
<$declarePackOcclusionDepth()$>
<$declareAmbientOcclusion()$>
// the source occlusion texture
uniform sampler2D occlusionMap;
@ -108,7 +129,6 @@ vec2 fetchOcclusionDepth(ivec2 coords) {
const int BLUR_RADIUS = 4;
const int RADIUS_SCALE = 2;
const float EDGE_SHARPNESS = 1.0;
const float gaussian[BLUR_RADIUS + 1] =
// float[](0.356642, 0.239400, 0.072410, 0.009869);
@ -139,7 +159,7 @@ vec3 getBlurredOcclusion(vec2 coord) {
float weight = 0.3 + gaussian[abs(r)];
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
weight *= max(0.0, 1.0 - (EDGE_SHARPNESS * 2000.0) * abs(tapOZ.y - key));
weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * 2000.0) * abs(tapOZ.y - key));
sum += tapOZ.x * weight;
totalWeight += weight;

View file

@ -13,9 +13,7 @@
<$declareAmbientOcclusion()$>
<$declarePackOcclusionDepth()$>
const int NUM_SAMPLES = 11;
const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES);
const int NUM_SPIRAL_TURNS= 7;
const int LOG_MAX_OFFSET = 3;
const int MAX_MIP_LEVEL = 5;
@ -32,10 +30,15 @@ out vec4 outFragColor;
uniform sampler2D normalMap;
float getAngleDithering(in ivec2 pixelPos) {
// Hash function used in the AlchemyAO paper
return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering();
}
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
// Radius relative to ssR
float alpha = float(sampleNumber + 0.5) * INV_NUM_SAMPLES;
float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
float angle = alpha * (getNumSpiralTurns() * 6.28) + spinAngle;
ssR = alpha;
return vec2(cos(angle), sin(angle));
@ -53,8 +56,8 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1));
// P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
P.z = -texelFetch(pyramidMap, ssP, 0).r;
P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
// P.z = -texelFetch(pyramidMap, ssP, 0).r;
// Offset to pixel center
//P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
@ -104,8 +107,7 @@ void main(void) {
vec3 Cp = evalEyePosition(varTexCoord0);
// Hash function used in the HPG12 AlchemyAO paper
float randomPatternRotationAngle = isDitheringEnabled() * (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10;
float randomPatternRotationAngle = getAngleDithering(ssC);
vec3 Cn = evalEyeNormal(Cp);
@ -114,11 +116,11 @@ void main(void) {
float ssDiskRadius = -getProjScale() * getRadius() / Cp.z;
float sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
for (int i = 0; i < getNumSamples(); ++i) {
sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
}
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * INV_NUM_SAMPLES);
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
// Bilateral box-filter over a quad for free, respecting depth edges
// (the difference that this makes is subtle)

View file

@ -76,7 +76,10 @@ public:
public:
float radius = 0.5f; // radius in meters of the AO effect
float level = 0.5f; // Level of the obscrance value
int numSamples = 11; // Num Samples per pixel
float numSpiralTurns = 7.0f;
bool ditheringEnabled = true;
float edgeSharpness = 1.0f;
};
RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);