Bilateral blur taps are evaluated in shader

This commit is contained in:
Olivier Prat 2018-09-25 11:06:05 +02:00
parent 0c586edeeb
commit 60f5913002
4 changed files with 13 additions and 82 deletions

View file

@ -199,61 +199,6 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() {
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() :
render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false),
#if SSAO_USE_HORIZON_BASED
@ -298,7 +243,6 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
void AmbientOcclusionEffect::configure(const Config& config) {
DependencyManager::get<DeferredLightingEffect>()->setAmbientOcclusionEnabled(config.enabled);
bool shouldUpdateGaussian = false;
bool shouldUpdateBlurs = false;
const double RADIUS_POWER = 6.0;
@ -332,7 +276,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
if (config.blurDeviation != _aoParametersBuffer->getBlurDeviation()) {
auto& current = _aoParametersBuffer.edit()._blurInfo;
current.z = config.blurDeviation;
shouldUpdateGaussian = true;
}
if (config.numSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) {
@ -386,7 +329,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
if (config.blurRadius != _aoParametersBuffer.get().getBlurRadius()) {
auto& current = _aoParametersBuffer.edit()._blurInfo;
current.y = (float)config.blurRadius;
shouldUpdateGaussian = true;
}
if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) {
@ -399,10 +341,6 @@ void AmbientOcclusionEffect::configure(const Config& config) {
current.w = (float)config.borderingEnabled;
}
if (shouldUpdateGaussian) {
updateGaussianDistribution();
}
if (shouldUpdateBlurs) {
updateBlurParameters();
}
@ -525,13 +463,6 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getBuildNormalsPipeline() {
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 {
// Having some problems making a nice AO with Half resolution depth, so stick to full res.
return 0;

View file

@ -175,7 +175,6 @@ private:
using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>;
void updateGaussianDistribution();
void updateBlurParameters();
void updateFramebufferSizes();

View file

@ -123,10 +123,6 @@ int getBlurRadius() {
return int(params._blurInfo.y);
}
float getBlurCoef(int c) {
return params._blurFilterTaps[c];
}
<@endfunc@>
<@func declareSamplingDisk()@>
@ -454,7 +450,12 @@ float fetchOcclusion(vec2 coords) {
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 tapPixelCoord = destPixelCoord + ivec2(tapOffset);
@ -467,11 +468,10 @@ vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 destPixelCoord, vec2 scaledTe
tapTexCoord = fullTexCoord + tapOffset * getDepthBlurScale();
float tapDepth = getZEyeAtUV(tapTexCoord, 0);
float weight = getBlurCoef(abs(r));
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
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);
}
@ -485,20 +485,23 @@ vec3 getBlurredOcclusion(ivec2 destPixelCoord, vec2 scaledTexCoord, vec2 fullTex
// Accumulate weighted contributions along the bluring axis in the [-radius, radius] range
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
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
float mainWeight = getBlurCoef(0);
float mainWeight = 1.0;
float pixelOcclusion = fetchOcclusion(scaledTexCoord);
weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight);
// then positive side
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

View file

@ -16,7 +16,6 @@
#define SSAO_USE_HORIZON_BASED 1
#define SSAO_USE_QUAD_SPLIT 1
#define SSAO_BLUR_GAUSSIAN_COEFS_COUNT 16
#if SSAO_USE_QUAD_SPLIT
#define SSAO_SPLIT_COUNT 4
@ -39,7 +38,6 @@ struct AmbientOcclusionParams {
SSAO_VEC4 _ditheringInfo;
SSAO_VEC4 _sampleInfo;
SSAO_VEC4 _blurInfo;
float _blurFilterTaps[SSAO_BLUR_GAUSSIAN_COEFS_COUNT];
SSAO_VEC4 _sideSizes[2];
};