mirror of
https://github.com/lubosz/overte.git
synced 2025-08-17 11:44:53 +02:00
Exposing many more controls of the AO in order to adjust the effect
This commit is contained in:
parent
89d2d102f6
commit
0285d48de3
8 changed files with 108 additions and 21 deletions
|
@ -109,6 +109,21 @@ panel.newSlider("Ambient Occlusion Level", 0.0, 1.0,
|
||||||
function() { return Render.ambientOcclusion.level; },
|
function() { return Render.ambientOcclusion.level; },
|
||||||
function (value) { return (value); });
|
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;
|
var tickTackPeriod = 500;
|
||||||
|
|
||||||
function updateCounters() {
|
function updateCounters() {
|
||||||
|
|
|
@ -177,11 +177,35 @@ void AmbientOcclusionEffect::setLevel(float level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AmbientOcclusionEffect::setDithering(bool enabled) {
|
void AmbientOcclusionEffect::setDithering(bool enabled) {
|
||||||
if (enabled != isDitheringEnabled()) {
|
if (enabled != isDitheringEnabled()) {
|
||||||
auto& current = _parametersBuffer.edit<Parameters>()._performanceCaps;
|
auto& current = _parametersBuffer.edit<Parameters>()._sampleInfo;
|
||||||
current.x = (float)enabled;
|
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());
|
setDepthInfo(args->_viewFrustum->getNearClip(), args->_viewFrustum->getFarClip());
|
||||||
_parametersBuffer.edit<Parameters>()._projection[0] = monoProjMat;
|
_parametersBuffer.edit<Parameters>()._projection[0] = monoProjMat;
|
||||||
_parametersBuffer.edit<Parameters>()._pixelInfo = args->_viewport;
|
_parametersBuffer.edit<Parameters>()._pixelInfo = args->_viewport;
|
||||||
|
_parametersBuffer.edit<Parameters>()._ditheringInfo.y += 0.25f;
|
||||||
|
|
||||||
|
|
||||||
auto pyramidPipeline = getPyramidPipeline();
|
auto pyramidPipeline = getPyramidPipeline();
|
||||||
auto occlusionPipeline = getOcclusionPipeline();
|
auto occlusionPipeline = getOcclusionPipeline();
|
||||||
|
|
|
@ -31,8 +31,19 @@ public:
|
||||||
float getLevel() const { return _parametersBuffer.get<Parameters>()._radiusInfo.w; }
|
float getLevel() const { return _parametersBuffer.get<Parameters>()._radiusInfo.w; }
|
||||||
|
|
||||||
void setDithering(bool enabled);
|
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>;
|
using JobModel = render::Task::Job::Model<AmbientOcclusionEffect>;
|
||||||
|
|
||||||
|
@ -45,8 +56,12 @@ private:
|
||||||
public:
|
public:
|
||||||
// radius info is { R, R^2, 1 / R^6, ObscuranceScale}
|
// 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 };
|
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
|
// Dithering info
|
||||||
glm::vec4 _performanceCaps{ 1.0, 1.0, 1.0, 1.0 };
|
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}
|
// Pixel info is { viemport width height and stereo on off}
|
||||||
glm::vec4 _pixelInfo;
|
glm::vec4 _pixelInfo;
|
||||||
// Depth info is { n.f, f - n, -f}
|
// Depth info is { n.f, f - n, -f}
|
||||||
|
|
|
@ -183,7 +183,10 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
|
||||||
if (_occlusionJobIndex >= 0) {
|
if (_occlusionJobIndex >= 0) {
|
||||||
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setRadius(renderContext->getAmbientOcclusion().radius);
|
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setRadius(renderContext->getAmbientOcclusion().radius);
|
||||||
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setLevel(renderContext->getAmbientOcclusion().level);
|
_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>().setDithering(renderContext->getAmbientOcclusion().ditheringEnabled);
|
||||||
|
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setEdgeSharpness(renderContext->getAmbientOcclusion().edgeSharpness);
|
||||||
}
|
}
|
||||||
|
|
||||||
setAntialiasingStatus(renderContext->getFxaaStatus());
|
setAntialiasingStatus(renderContext->getFxaaStatus());
|
||||||
|
|
|
@ -72,7 +72,10 @@ namespace RenderScripting {
|
||||||
public:
|
public:
|
||||||
Q_PROPERTY(float radius MEMBER radius)
|
Q_PROPERTY(float radius MEMBER radius)
|
||||||
Q_PROPERTY(float level MEMBER level)
|
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(bool ditheringEnabled MEMBER ditheringEnabled)
|
||||||
|
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness)
|
||||||
};
|
};
|
||||||
using AmbientOcclusionPointer = std::unique_ptr<AmbientOcclusion>;
|
using AmbientOcclusionPointer = std::unique_ptr<AmbientOcclusion>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,9 @@ vec2 unpackOcclusionDepth(vec3 raw) {
|
||||||
|
|
||||||
struct AmbientOcclusionParams {
|
struct AmbientOcclusionParams {
|
||||||
vec4 _radiusInfo;
|
vec4 _radiusInfo;
|
||||||
vec4 _performanceCaps;
|
vec4 _ditheringInfo;
|
||||||
|
vec4 _sampleInfo;
|
||||||
|
vec4 _blurInfo;
|
||||||
vec4 _pixelInfo;
|
vec4 _pixelInfo;
|
||||||
vec4 _depthInfo;
|
vec4 _depthInfo;
|
||||||
mat4 _projection[2];
|
mat4 _projection[2];
|
||||||
|
@ -67,7 +69,25 @@ float getObscuranceScaling() {
|
||||||
}
|
}
|
||||||
|
|
||||||
float isDitheringEnabled() {
|
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) {
|
float evalZeyeFromZdb(float depth) {
|
||||||
|
@ -92,6 +112,7 @@ vec3 evalEyeNormal(vec3 C) {
|
||||||
<@func declareBlurPass(axis)@>
|
<@func declareBlurPass(axis)@>
|
||||||
|
|
||||||
<$declarePackOcclusionDepth()$>
|
<$declarePackOcclusionDepth()$>
|
||||||
|
<$declareAmbientOcclusion()$>
|
||||||
|
|
||||||
// the source occlusion texture
|
// the source occlusion texture
|
||||||
uniform sampler2D occlusionMap;
|
uniform sampler2D occlusionMap;
|
||||||
|
@ -108,7 +129,6 @@ vec2 fetchOcclusionDepth(ivec2 coords) {
|
||||||
|
|
||||||
const int BLUR_RADIUS = 4;
|
const int BLUR_RADIUS = 4;
|
||||||
const int RADIUS_SCALE = 2;
|
const int RADIUS_SCALE = 2;
|
||||||
const float EDGE_SHARPNESS = 1.0;
|
|
||||||
|
|
||||||
const float gaussian[BLUR_RADIUS + 1] =
|
const float gaussian[BLUR_RADIUS + 1] =
|
||||||
// float[](0.356642, 0.239400, 0.072410, 0.009869);
|
// float[](0.356642, 0.239400, 0.072410, 0.009869);
|
||||||
|
@ -139,7 +159,7 @@ vec3 getBlurredOcclusion(vec2 coord) {
|
||||||
float weight = 0.3 + gaussian[abs(r)];
|
float weight = 0.3 + gaussian[abs(r)];
|
||||||
|
|
||||||
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
// 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;
|
sum += tapOZ.x * weight;
|
||||||
totalWeight += weight;
|
totalWeight += weight;
|
||||||
|
|
|
@ -13,9 +13,7 @@
|
||||||
<$declareAmbientOcclusion()$>
|
<$declareAmbientOcclusion()$>
|
||||||
<$declarePackOcclusionDepth()$>
|
<$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 LOG_MAX_OFFSET = 3;
|
||||||
const int MAX_MIP_LEVEL = 5;
|
const int MAX_MIP_LEVEL = 5;
|
||||||
|
|
||||||
|
@ -32,10 +30,15 @@ out vec4 outFragColor;
|
||||||
|
|
||||||
uniform sampler2D normalMap;
|
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){
|
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
|
||||||
// Radius relative to ssR
|
// Radius relative to ssR
|
||||||
float alpha = float(sampleNumber + 0.5) * INV_NUM_SAMPLES;
|
float alpha = float(sampleNumber + 0.5) * getInvNumSamples();
|
||||||
float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
|
float angle = alpha * (getNumSpiralTurns() * 6.28) + spinAngle;
|
||||||
|
|
||||||
ssR = alpha;
|
ssR = alpha;
|
||||||
return vec2(cos(angle), sin(angle));
|
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.
|
// 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
|
// Manually clamp to the texture size because texelFetch bypasses the texture unit
|
||||||
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1));
|
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1));
|
||||||
// P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
|
P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
|
||||||
P.z = -texelFetch(pyramidMap, ssP, 0).r;
|
// P.z = -texelFetch(pyramidMap, ssP, 0).r;
|
||||||
|
|
||||||
// Offset to pixel center
|
// Offset to pixel center
|
||||||
//P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
|
//P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
|
||||||
|
@ -104,8 +107,7 @@ void main(void) {
|
||||||
|
|
||||||
vec3 Cp = evalEyePosition(varTexCoord0);
|
vec3 Cp = evalEyePosition(varTexCoord0);
|
||||||
|
|
||||||
// Hash function used in the HPG12 AlchemyAO paper
|
float randomPatternRotationAngle = getAngleDithering(ssC);
|
||||||
float randomPatternRotationAngle = isDitheringEnabled() * (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10;
|
|
||||||
|
|
||||||
vec3 Cn = evalEyeNormal(Cp);
|
vec3 Cn = evalEyeNormal(Cp);
|
||||||
|
|
||||||
|
@ -114,11 +116,11 @@ void main(void) {
|
||||||
float ssDiskRadius = -getProjScale() * getRadius() / Cp.z;
|
float ssDiskRadius = -getProjScale() * getRadius() / Cp.z;
|
||||||
|
|
||||||
float sum = 0.0;
|
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);
|
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
|
// Bilateral box-filter over a quad for free, respecting depth edges
|
||||||
// (the difference that this makes is subtle)
|
// (the difference that this makes is subtle)
|
||||||
|
|
|
@ -76,7 +76,10 @@ public:
|
||||||
public:
|
public:
|
||||||
float radius = 0.5f; // radius in meters of the AO effect
|
float radius = 0.5f; // radius in meters of the AO effect
|
||||||
float level = 0.5f; // Level of the obscrance value
|
float level = 0.5f; // Level of the obscrance value
|
||||||
|
int numSamples = 11; // Num Samples per pixel
|
||||||
|
float numSpiralTurns = 7.0f;
|
||||||
bool ditheringEnabled = true;
|
bool ditheringEnabled = true;
|
||||||
|
float edgeSharpness = 1.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);
|
RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);
|
||||||
|
|
Loading…
Reference in a new issue