mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 23:36:44 +02:00
Bilateral blur taps are evaluated in shader
This commit is contained in:
parent
0c586edeeb
commit
60f5913002
4 changed files with 13 additions and 82 deletions
|
@ -199,61 +199,6 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
|
||||||
return _normalTexture;
|
return _normalTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
class GaussianDistribution {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static double integral(float x, float deviation) {
|
|
||||||
return 0.5 * erf((double)x / ((double)deviation * sqrt(2.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static double rangeIntegral(float x0, float x1, float deviation) {
|
|
||||||
return integral(x1, deviation) - integral(x0, deviation);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<float> evalSampling(int samplingRadius, float deviation) {
|
|
||||||
std::vector<float> coefs(samplingRadius + 1, 0.0f);
|
|
||||||
|
|
||||||
// corner case when radius is 0 or under
|
|
||||||
if (samplingRadius <= 0) {
|
|
||||||
coefs[0] = 1.0f;
|
|
||||||
return coefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate all the samples range integral of width 1 from center until the penultimate one
|
|
||||||
float halfWidth = 0.5f;
|
|
||||||
double sum = 0.0;
|
|
||||||
for (int i = 0; i < samplingRadius; i++) {
|
|
||||||
float x = (float) i;
|
|
||||||
double sample = rangeIntegral(x - halfWidth, x + halfWidth, deviation);
|
|
||||||
coefs[i] = sample;
|
|
||||||
sum += sample;
|
|
||||||
}
|
|
||||||
|
|
||||||
// last sample goes to infinity
|
|
||||||
float lastSampleX0 = (float) samplingRadius - halfWidth;
|
|
||||||
float largeEnough = lastSampleX0 + 1000.0f * deviation;
|
|
||||||
double sample = rangeIntegral(lastSampleX0, largeEnough, deviation);
|
|
||||||
coefs[samplingRadius] = sample;
|
|
||||||
sum += sample;
|
|
||||||
|
|
||||||
return coefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void evalSampling(float* coefs, unsigned int coefsLength, int samplingRadius, float deviation) {
|
|
||||||
auto coefsVector = evalSampling(samplingRadius, deviation);
|
|
||||||
if (coefsLength> coefsVector.size() + 1) {
|
|
||||||
unsigned int coefsNum = 0;
|
|
||||||
for (auto s : coefsVector) {
|
|
||||||
coefs[coefsNum] = s;
|
|
||||||
coefsNum++;
|
|
||||||
}
|
|
||||||
for (;coefsNum < coefsLength; coefsNum++) {
|
|
||||||
coefs[coefsNum] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() :
|
||||||
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
|
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
|
||||||
#if SSAO_USE_HORIZON_BASED
|
#if SSAO_USE_HORIZON_BASED
|
||||||
|
@ -298,7 +243,6 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
|
||||||
void AmbientOcclusionEffect::configure(const Config& config) {
|
void AmbientOcclusionEffect::configure(const Config& config) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
|
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
|
||||||
|
|
||||||
bool shouldUpdateGaussian = false;
|
|
||||||
bool shouldUpdateBlurs = false;
|
bool shouldUpdateBlurs = false;
|
||||||
|
|
||||||
const double RADIUS_POWER = 6.0;
|
const double RADIUS_POWER = 6.0;
|
||||||
|
@ -332,7 +276,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
||||||
if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) {
|
if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) {
|
||||||
auto& current = _aoParametersBuffer.edit()._blurInfo;
|
auto& current = _aoParametersBuffer.edit()._blurInfo;
|
||||||
current.z = config.blurDeviation;
|
current.z = config.blurDeviation;
|
||||||
shouldUpdateGaussian = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) {
|
if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) {
|
||||||
|
@ -386,7 +329,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
||||||
if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) {
|
if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) {
|
||||||
auto& current = _aoParametersBuffer.edit()._blurInfo;
|
auto& current = _aoParametersBuffer.edit()._blurInfo;
|
||||||
current.y = (float)config.blurRadius;
|
current.y = (float)config.blurRadius;
|
||||||
shouldUpdateGaussian = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) {
|
if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) {
|
||||||
|
@ -399,10 +341,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
|
||||||
current.w = (float)config.borderingEnabled;
|
current.w = (float)config.borderingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldUpdateGaussian) {
|
|
||||||
updateGaussianDistribution();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldUpdateBlurs) {
|
if (shouldUpdateBlurs) {
|
||||||
updateBlurParameters();
|
updateBlurParameters();
|
||||||
}
|
}
|
||||||
|
@ -525,13 +463,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() {
|
||||||
return _buildNormalsPipeline;
|
return _buildNormalsPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmbientOcclusionEffect::updateGaussianDistribution() {
|
|
||||||
auto filterTaps = _aoParametersBuffer.edit()._blurFilterTaps;
|
|
||||||
auto blurRadius = _aoParametersBuffer.get().getBlurRadius();
|
|
||||||
|
|
||||||
GaussianDistribution::evalSampling(filterTaps, SSAO_BLUR_GAUSSIAN_COEFS_COUNT, blurRadius, _aoParametersBuffer->getBlurDeviation());
|
|
||||||
}
|
|
||||||
|
|
||||||
int AmbientOcclusionEffect::getDepthResolutionLevel() const {
|
int AmbientOcclusionEffect::getDepthResolutionLevel() const {
|
||||||
// Having some problems making a nice AO with Half resolution depth, so stick to full res.
|
// Having some problems making a nice AO with Half resolution depth, so stick to full res.
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -175,7 +175,6 @@ private:
|
||||||
|
|
||||||
using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>;
|
using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>;
|
||||||
|
|
||||||
void updateGaussianDistribution();
|
|
||||||
void updateBlurParameters();
|
void updateBlurParameters();
|
||||||
void updateFramebufferSizes();
|
void updateFramebufferSizes();
|
||||||
|
|
||||||
|
|
|
@ -123,10 +123,6 @@ int getBlurRadius() {
|
||||||
return int(params._blurInfo.y);
|
return int(params._blurInfo.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBlurCoef(int c) {
|
|
||||||
return params._blurFilterTaps[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
<@func declareSamplingDisk()@>
|
<@func declareSamplingDisk()@>
|
||||||
|
@ -454,7 +450,12 @@ float fetchOcclusion(vec2 coords) {
|
||||||
|
|
||||||
const float BLUR_EDGE_DISTANCE_SCALE = 1000.0;
|
const float BLUR_EDGE_DISTANCE_SCALE = 1000.0;
|
||||||
|
|
||||||
vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) {
|
float evalBlurCoefficient(vec2 blurScales, float radialDistance, float zDistance) {
|
||||||
|
vec2 distances = vec2(radialDistance, zDistance);
|
||||||
|
return exp2(dot(blurScales, distances*distances));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 evalTapWeightedValue(vec2 blurScales, ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTexCoord, float fragDepth) {
|
||||||
ivec2 tapOffset = <$axis$> * r;
|
ivec2 tapOffset = <$axis$> * r;
|
||||||
ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset);
|
ivec2 tapPixelCoord = destPixelCoord + ivec2(tapOffset);
|
||||||
|
|
||||||
|
@ -467,11 +468,10 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe
|
||||||
|
|
||||||
tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale();
|
tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale();
|
||||||
float tapDepth = getZEyeAtUV(tapTexCoord, 0);
|
float tapDepth = getZEyeAtUV(tapTexCoord, 0);
|
||||||
float weight = getBlurCoef(abs(r));
|
|
||||||
|
|
||||||
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
||||||
float zDistance = tapDepth - fragDepth;
|
float zDistance = tapDepth - fragDepth;
|
||||||
weight *= exp(-getBlurEdgeSharpness() * (zDistance * zDistance * BLUR_EDGE_DISTANCE_SCALE));
|
float weight = evalBlurCoefficient(blurScales, abs(r), zDistance);
|
||||||
|
|
||||||
return vec2(tapOcclusion * weight, weight);
|
return vec2(tapOcclusion * weight, weight);
|
||||||
}
|
}
|
||||||
|
@ -485,20 +485,23 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex
|
||||||
|
|
||||||
// Accumulate weighted contributions along the bluring axis in the [-radius, radius] range
|
// Accumulate weighted contributions along the bluring axis in the [-radius, radius] range
|
||||||
int blurRadius = getBlurRadius();
|
int blurRadius = getBlurRadius();
|
||||||
|
float blurRadialSigma = float(blurRadius) * 0.5;
|
||||||
|
float blurRadialScale = 1.0 / (2.0*blurRadialSigma*blurRadialSigma);
|
||||||
|
vec2 blurScales = -vec2(blurRadialScale, BLUR_EDGE_DISTANCE_SCALE) * getBlurEdgeSharpness();
|
||||||
|
|
||||||
// negative side first
|
// negative side first
|
||||||
for (int r = -blurRadius; r <= -1; ++r) {
|
for (int r = -blurRadius; r <= -1; ++r) {
|
||||||
weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth);
|
weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Central pixel contribution
|
// Central pixel contribution
|
||||||
float mainWeight = getBlurCoef(0);
|
float mainWeight = 1.0;
|
||||||
float pixelOcclusion = fetchOcclusion(scaledTexCoord);
|
float pixelOcclusion = fetchOcclusion(scaledTexCoord);
|
||||||
weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight);
|
weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight);
|
||||||
|
|
||||||
// then positive side
|
// then positive side
|
||||||
for (int r = 1; r <= blurRadius; ++r) {
|
for (int r = 1; r <= blurRadius; ++r) {
|
||||||
weightedSums += evalTapWeightedValue(side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth);
|
weightedSums += evalTapWeightedValue(blurScales, side.xyz, r, destPixelCoord, scaledTexCoord, fullTexCoord, fragDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final normalization
|
// Final normalization
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#define SSAO_USE_HORIZON_BASED 1
|
#define SSAO_USE_HORIZON_BASED 1
|
||||||
#define SSAO_USE_QUAD_SPLIT 1
|
#define SSAO_USE_QUAD_SPLIT 1
|
||||||
#define SSAO_BLUR_GAUSSIAN_COEFS_COUNT 16
|
|
||||||
|
|
||||||
#if SSAO_USE_QUAD_SPLIT
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
#define SSAO_SPLIT_COUNT 4
|
#define SSAO_SPLIT_COUNT 4
|
||||||
|
@ -39,7 +38,6 @@ struct AmbientOcclusionParams {
|
||||||
SSAO_VEC4 _ditheringInfo;
|
SSAO_VEC4 _ditheringInfo;
|
||||||
SSAO_VEC4 _sampleInfo;
|
SSAO_VEC4 _sampleInfo;
|
||||||
SSAO_VEC4 _blurInfo;
|
SSAO_VEC4 _blurInfo;
|
||||||
float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT];
|
|
||||||
SSAO_VEC4 _sideSizes[2];
|
SSAO_VEC4 _sideSizes[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue