mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 21:12:53 +02:00
commit
83660ab8e1
40 changed files with 1890 additions and 840 deletions
|
@ -329,6 +329,8 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) {
|
||||||
result = GL_RGBA8_SNORM;
|
result = GL_RGBA8_SNORM;
|
||||||
break;
|
break;
|
||||||
case gpu::NINT2_10_10_10:
|
case gpu::NINT2_10_10_10:
|
||||||
|
result = GL_RGB10_A2;
|
||||||
|
break;
|
||||||
case gpu::NUINT32:
|
case gpu::NUINT32:
|
||||||
case gpu::NINT32:
|
case gpu::NINT32:
|
||||||
case gpu::COMPRESSED:
|
case gpu::COMPRESSED:
|
||||||
|
@ -729,9 +731,9 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
||||||
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
texel.internalFormat = GL_DEPTH_COMPONENT24;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case gpu::NINT2_10_10_10:
|
||||||
case gpu::COMPRESSED:
|
case gpu::COMPRESSED:
|
||||||
case gpu::NUINT2:
|
case gpu::NUINT2:
|
||||||
case gpu::NINT2_10_10_10:
|
|
||||||
case gpu::NUM_TYPES: { // quiet compiler
|
case gpu::NUM_TYPES: { // quiet compiler
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -893,9 +895,12 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E
|
||||||
texel.format = GL_RGBA;
|
texel.format = GL_RGBA;
|
||||||
texel.internalFormat = GL_RGBA2;
|
texel.internalFormat = GL_RGBA2;
|
||||||
break;
|
break;
|
||||||
|
case gpu::NINT2_10_10_10:
|
||||||
|
texel.format = GL_RGBA;
|
||||||
|
texel.internalFormat = GL_RGB10_A2;
|
||||||
|
break;
|
||||||
case gpu::NUINT32:
|
case gpu::NUINT32:
|
||||||
case gpu::NINT32:
|
case gpu::NINT32:
|
||||||
case gpu::NINT2_10_10_10:
|
|
||||||
case gpu::COMPRESSED:
|
case gpu::COMPRESSED:
|
||||||
case gpu::NUM_TYPES: // quiet compiler
|
case gpu::NUM_TYPES: // quiet compiler
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
|
|
|
@ -49,26 +49,7 @@ void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) {
|
||||||
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
||||||
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
if (isStereo()) {
|
draw(mode, numVertices, startVertex);
|
||||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
|
||||||
glDrawArraysInstanced(mode, startVertex, numVertices, 2);
|
|
||||||
#else
|
|
||||||
setupStereoSide(0);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
setupStereoSide(1);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
#endif
|
|
||||||
_stats._DSNumTriangles += 2 * numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls += 2;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
_stats._DSNumTriangles += numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls++;
|
|
||||||
}
|
|
||||||
_stats._DSNumAPIDrawcalls++;
|
|
||||||
|
|
||||||
(void) CHECK_GL_ERROR();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL41Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
void GL41Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
|
@ -72,27 +72,7 @@ void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) {
|
||||||
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
||||||
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
if (isStereo()) {
|
draw(mode, numVertices, startVertex);
|
||||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
|
||||||
glDrawArraysInstanced(mode, startVertex, numVertices, 2);
|
|
||||||
#else
|
|
||||||
setupStereoSide(0);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
setupStereoSide(1);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_stats._DSNumTriangles += 2 * numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls += 2;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
_stats._DSNumTriangles += numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls++;
|
|
||||||
}
|
|
||||||
_stats._DSNumAPIDrawcalls++;
|
|
||||||
|
|
||||||
(void) CHECK_GL_ERROR();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
void GL45Backend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
|
@ -49,28 +49,7 @@ void GLESBackend::do_draw(const Batch& batch, size_t paramOffset) {
|
||||||
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
uint32 numVertices = batch._params[paramOffset + 1]._uint;
|
||||||
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
uint32 startVertex = batch._params[paramOffset + 0]._uint;
|
||||||
|
|
||||||
if (isStereo()) {
|
draw(mode, numVertices, startVertex);
|
||||||
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
|
|
||||||
glDrawArraysInstanced(mode, startVertex, numVertices, 2);
|
|
||||||
#else
|
|
||||||
|
|
||||||
setupStereoSide(0);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
setupStereoSide(1);
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
_stats._DSNumTriangles += 2 * numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls += 2;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
glDrawArrays(mode, startVertex, numVertices);
|
|
||||||
_stats._DSNumTriangles += numVertices / 3;
|
|
||||||
_stats._DSNumDrawcalls++;
|
|
||||||
}
|
|
||||||
_stats._DSNumAPIDrawcalls++;
|
|
||||||
|
|
||||||
(void) CHECK_GL_ERROR();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLESBackend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
void GLESBackend::do_drawIndexed(const Batch& batch, size_t paramOffset) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include "ShaderConstants.h"
|
||||||
|
|
||||||
#include "GPULogging.h"
|
#include "GPULogging.h"
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "Frame.h"
|
#include "Frame.h"
|
||||||
#include "GPULogging.h"
|
#include "GPULogging.h"
|
||||||
|
#include <shaders/Shaders.h>
|
||||||
|
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
|
||||||
|
@ -331,11 +332,20 @@ Size Context::getTextureResourcePopulatedGPUMemSize() {
|
||||||
return Backend::textureResourcePopulatedGPUMemSize.getValue();
|
return Backend::textureResourcePopulatedGPUMemSize.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PipelinePointer Context::createMipGenerationPipeline(const ShaderPointer& ps) {
|
||||||
|
auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawViewportQuadTransformTexcoord);
|
||||||
|
static gpu::StatePointer state(new gpu::State());
|
||||||
|
|
||||||
|
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||||
|
|
||||||
|
// Good to go add the brand new pipeline
|
||||||
|
return gpu::Pipeline::create(program, state);
|
||||||
|
}
|
||||||
|
|
||||||
Size Context::getTextureResourceIdealGPUMemSize() {
|
Size Context::getTextureResourceIdealGPUMemSize() {
|
||||||
return Backend::textureResourceIdealGPUMemSize.getValue();
|
return Backend::textureResourceIdealGPUMemSize.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BatchPointer Context::acquireBatch(const char* name) {
|
BatchPointer Context::acquireBatch(const char* name) {
|
||||||
Batch* rawBatch = nullptr;
|
Batch* rawBatch = nullptr;
|
||||||
{
|
{
|
||||||
|
|
|
@ -218,6 +218,8 @@ public:
|
||||||
// Same as above but grabbed at every end of a frame
|
// Same as above but grabbed at every end of a frame
|
||||||
void getFrameStats(ContextStats& stats) const;
|
void getFrameStats(ContextStats& stats) const;
|
||||||
|
|
||||||
|
static PipelinePointer createMipGenerationPipeline(const ShaderPointer& pixelShader);
|
||||||
|
|
||||||
double getFrameTimerGPUAverage() const;
|
double getFrameTimerGPUAverage() const;
|
||||||
double getFrameTimerBatchAverage() const;
|
double getFrameTimerBatchAverage() const;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,6 +21,8 @@
|
||||||
#include "DeferredFramebuffer.h"
|
#include "DeferredFramebuffer.h"
|
||||||
#include "SurfaceGeometryPass.h"
|
#include "SurfaceGeometryPass.h"
|
||||||
|
|
||||||
|
#include "ssao_shared.h"
|
||||||
|
|
||||||
class AmbientOcclusionFramebuffer {
|
class AmbientOcclusionFramebuffer {
|
||||||
public:
|
public:
|
||||||
AmbientOcclusionFramebuffer();
|
AmbientOcclusionFramebuffer();
|
||||||
|
@ -30,13 +32,23 @@ public:
|
||||||
|
|
||||||
gpu::FramebufferPointer getOcclusionBlurredFramebuffer();
|
gpu::FramebufferPointer getOcclusionBlurredFramebuffer();
|
||||||
gpu::TexturePointer getOcclusionBlurredTexture();
|
gpu::TexturePointer getOcclusionBlurredTexture();
|
||||||
|
|
||||||
|
gpu::FramebufferPointer getNormalFramebuffer();
|
||||||
|
gpu::TexturePointer getNormalTexture();
|
||||||
|
|
||||||
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
|
gpu::FramebufferPointer getOcclusionSplitFramebuffer(int index);
|
||||||
|
gpu::TexturePointer getOcclusionSplitTexture();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
||||||
void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer);
|
bool update(const gpu::TexturePointer& linearDepthBuffer, int resolutionLevel, int depthResolutionLevel, bool isStereo);
|
||||||
gpu::TexturePointer getLinearDepthTexture();
|
gpu::TexturePointer getLinearDepthTexture();
|
||||||
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
||||||
|
bool isStereo() const { return _isStereo; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
void allocate();
|
void allocate();
|
||||||
|
|
||||||
|
@ -44,12 +56,22 @@ protected:
|
||||||
|
|
||||||
gpu::FramebufferPointer _occlusionFramebuffer;
|
gpu::FramebufferPointer _occlusionFramebuffer;
|
||||||
gpu::TexturePointer _occlusionTexture;
|
gpu::TexturePointer _occlusionTexture;
|
||||||
|
|
||||||
gpu::FramebufferPointer _occlusionBlurredFramebuffer;
|
gpu::FramebufferPointer _occlusionBlurredFramebuffer;
|
||||||
gpu::TexturePointer _occlusionBlurredTexture;
|
gpu::TexturePointer _occlusionBlurredTexture;
|
||||||
|
|
||||||
|
gpu::FramebufferPointer _normalFramebuffer;
|
||||||
|
gpu::TexturePointer _normalTexture;
|
||||||
|
|
||||||
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
|
gpu::FramebufferPointer _occlusionSplitFramebuffers[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT];
|
||||||
|
gpu::TexturePointer _occlusionSplitTexture;
|
||||||
|
#endif
|
||||||
|
|
||||||
glm::ivec2 _frameSize;
|
glm::ivec2 _frameSize;
|
||||||
|
int _resolutionLevel{ 0 };
|
||||||
|
int _depthResolutionLevel{ 0 };
|
||||||
|
bool _isStereo{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFramebuffer>;
|
using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFramebuffer>;
|
||||||
|
@ -57,53 +79,78 @@ using AmbientOcclusionFramebufferPointer = std::shared_ptr<AmbientOcclusionFrame
|
||||||
class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
|
class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||||
|
Q_PROPERTY(bool horizonBased MEMBER horizonBased NOTIFY dirty)
|
||||||
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
||||||
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
|
Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty)
|
||||||
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty)
|
Q_PROPERTY(bool fetchMipsEnabled MEMBER fetchMipsEnabled NOTIFY dirty)
|
||||||
Q_PROPERTY(float radius MEMBER radius WRITE setRadius)
|
Q_PROPERTY(bool jitterEnabled MEMBER jitterEnabled NOTIFY dirty)
|
||||||
Q_PROPERTY(float obscuranceLevel MEMBER obscuranceLevel WRITE setObscuranceLevel)
|
|
||||||
Q_PROPERTY(float falloffBias MEMBER falloffBias WRITE setFalloffBias)
|
|
||||||
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(int resolutionLevel MEMBER resolutionLevel WRITE setResolutionLevel)
|
||||||
|
Q_PROPERTY(float edgeSharpness MEMBER edgeSharpness WRITE setEdgeSharpness)
|
||||||
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
|
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:
|
public:
|
||||||
AmbientOcclusionEffectConfig() : render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion", false) {}
|
AmbientOcclusionEffectConfig();
|
||||||
|
|
||||||
const int MAX_RESOLUTION_LEVEL = 4;
|
const int MAX_RESOLUTION_LEVEL = 4;
|
||||||
const int MAX_BLUR_RADIUS = 6;
|
const int MAX_BLUR_RADIUS = 15;
|
||||||
|
|
||||||
void setRadius(float newRadius) { radius = std::max(0.01f, newRadius); emit dirty(); }
|
void setEdgeSharpness(float sharpness);
|
||||||
void setObscuranceLevel(float level) { obscuranceLevel = std::max(0.01f, level); emit dirty(); }
|
void setResolutionLevel(int level);
|
||||||
void setFalloffBias(float bias) { falloffBias = std::max(0.0f, std::min(bias, 0.2f)); emit dirty(); }
|
void setBlurRadius(int radius);
|
||||||
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(); }
|
|
||||||
|
|
||||||
float radius{ 0.5f };
|
void setSSAORadius(float newRadius);
|
||||||
float perspectiveScale{ 1.0f };
|
void setSSAOObscuranceLevel(float level);
|
||||||
float obscuranceLevel{ 0.5f }; // intensify or dim down the obscurance effect
|
void setSSAOFalloffAngle(float bias);
|
||||||
float falloffBias{ 0.01f };
|
void setSSAONumSpiralTurns(float turns);
|
||||||
float edgeSharpness{ 1.0f };
|
void setSSAONumSamples(int samples);
|
||||||
float blurDeviation{ 2.5f };
|
|
||||||
float numSpiralTurns{ 7.0f }; // defining an angle span to distribute the samples ray directions
|
void setHBAORadius(float newRadius);
|
||||||
int numSamples{ 16 };
|
void setHBAOObscuranceLevel(float level);
|
||||||
int resolutionLevel{ 1 };
|
void setHBAOFalloffAngle(float bias);
|
||||||
int blurRadius{ 4 }; // 0 means no blurring
|
void setHBAONumSamples(int samples);
|
||||||
bool ditheringEnabled{ true }; // randomize the distribution of taps per pixel, should always be true
|
|
||||||
bool borderingEnabled{ true }; // avoid evaluating information from non existing pixels out of the frame, should always be true
|
float perspectiveScale;
|
||||||
bool fetchMipsEnabled{ true }; // fetch taps in sub mips to otpimize cache, should always be true
|
float edgeSharpness;
|
||||||
|
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
|
||||||
|
bool fetchMipsEnabled; // fetch taps in sub mips to otpimize cache, should always be true
|
||||||
|
bool jitterEnabled; // Add small jittering to AO samples at each frame
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dirty();
|
void dirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define SSAO_RANDOM_SAMPLE_COUNT 16
|
||||||
|
|
||||||
class AmbientOcclusionEffect {
|
class AmbientOcclusionEffect {
|
||||||
public:
|
public:
|
||||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer>;
|
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer>;
|
||||||
|
@ -115,59 +162,75 @@ public:
|
||||||
|
|
||||||
void configure(const Config& config);
|
void configure(const Config& config);
|
||||||
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs);
|
||||||
|
|
||||||
|
|
||||||
// Class describing the uniform buffer with all the parameters common to the AO shaders
|
// Class describing the uniform buffer with all the parameters common to the AO shaders
|
||||||
class Parameters {
|
class AOParameters : public AmbientOcclusionParams {
|
||||||
public:
|
public:
|
||||||
// Resolution info
|
|
||||||
glm::vec4 resolutionInfo { -1.0f, 0.0f, 1.0f, 0.0f };
|
|
||||||
// radius info is { R, R^2, 1 / R^6, ObscuranceScale}
|
|
||||||
glm::vec4 radiusInfo{ 0.5f, 0.5f * 0.5f, 1.0f / (0.25f * 0.25f * 0.25f), 1.0f };
|
|
||||||
// Dithering info
|
|
||||||
glm::vec4 ditheringInfo { 0.0f, 0.0f, 0.01f, 1.0f };
|
|
||||||
// Sampling info
|
|
||||||
glm::vec4 sampleInfo { 11.0f, 1.0f/11.0f, 7.0f, 1.0f };
|
|
||||||
// Blurring info
|
|
||||||
glm::vec4 blurInfo { 1.0f, 3.0f, 2.0f, 0.0f };
|
|
||||||
// gaussian distribution coefficients first is the sampling radius (max is 6)
|
|
||||||
const static int GAUSSIAN_COEFS_LENGTH = 8;
|
|
||||||
float _gaussianCoefs[GAUSSIAN_COEFS_LENGTH];
|
|
||||||
|
|
||||||
Parameters() {}
|
|
||||||
|
|
||||||
int getResolutionLevel() const { return resolutionInfo.x; }
|
AOParameters();
|
||||||
float getRadius() const { return radiusInfo.x; }
|
|
||||||
float getPerspectiveScale() const { return resolutionInfo.z; }
|
int getResolutionLevel() const { return _resolutionInfo.x; }
|
||||||
float getObscuranceLevel() const { return radiusInfo.w; }
|
float getRadius() const { return _radiusInfo.x; }
|
||||||
float getFalloffBias() const { return (float)ditheringInfo.z; }
|
float getPerspectiveScale() const { return _resolutionInfo.z; }
|
||||||
float getEdgeSharpness() const { return (float)blurInfo.x; }
|
float getObscuranceLevel() const { return _radiusInfo.w; }
|
||||||
float getBlurDeviation() const { return blurInfo.z; }
|
float getFalloffAngle() const { return (float)_falloffInfo.x; }
|
||||||
|
|
||||||
float getNumSpiralTurns() const { return sampleInfo.z; }
|
float getNumSpiralTurns() const { return _sampleInfo.z; }
|
||||||
int getNumSamples() const { return (int)sampleInfo.x; }
|
int getNumSamples() const { return (int)_sampleInfo.x; }
|
||||||
bool isFetchMipsEnabled() const { return sampleInfo.w; }
|
bool isFetchMipsEnabled() const { return _sampleInfo.w; }
|
||||||
|
|
||||||
|
bool isDitheringEnabled() const { return _ditheringInfo.x != 0.0f; }
|
||||||
|
bool isBorderingEnabled() const { return _ditheringInfo.w != 0.0f; }
|
||||||
|
bool isHorizonBased() const { return _resolutionInfo.y != 0.0f; }
|
||||||
|
|
||||||
int getBlurRadius() const { return (int)blurInfo.y; }
|
|
||||||
bool isDitheringEnabled() const { return ditheringInfo.x; }
|
|
||||||
bool isBorderingEnabled() const { return ditheringInfo.w; }
|
|
||||||
};
|
};
|
||||||
using ParametersBuffer = gpu::StructBuffer<Parameters>;
|
using AOParametersBuffer = gpu::StructBuffer<AOParameters>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateGaussianDistribution();
|
|
||||||
|
|
||||||
ParametersBuffer _parametersBuffer;
|
|
||||||
|
|
||||||
const gpu::PipelinePointer& getOcclusionPipeline();
|
// Class describing the uniform buffer with all the parameters common to the bilateral blur shaders
|
||||||
const gpu::PipelinePointer& getHBlurPipeline(); // first
|
class BlurParameters : public AmbientOcclusionBlurParams {
|
||||||
const gpu::PipelinePointer& getVBlurPipeline(); // second
|
public:
|
||||||
|
|
||||||
gpu::PipelinePointer _occlusionPipeline;
|
BlurParameters();
|
||||||
gpu::PipelinePointer _hBlurPipeline;
|
|
||||||
gpu::PipelinePointer _vBlurPipeline;
|
float getEdgeSharpness() const { return (float)_blurInfo.x; }
|
||||||
|
int getBlurRadius() const { return (int)_blurInfo.w; }
|
||||||
|
|
||||||
|
};
|
||||||
|
using BlurParametersBuffer = gpu::StructBuffer<BlurParameters>;
|
||||||
|
|
||||||
|
using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>;
|
||||||
|
|
||||||
|
void updateBlurParameters();
|
||||||
|
void updateFramebufferSizes();
|
||||||
|
void updateRandomSamples();
|
||||||
|
void updateJitterSamples();
|
||||||
|
|
||||||
|
int getDepthResolutionLevel() const;
|
||||||
|
|
||||||
|
AOParametersBuffer _aoParametersBuffer;
|
||||||
|
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();
|
||||||
|
static const gpu::PipelinePointer& getMipCreationPipeline();
|
||||||
|
static const gpu::PipelinePointer& getGatherPipeline();
|
||||||
|
static const gpu::PipelinePointer& getBuildNormalsPipeline();
|
||||||
|
|
||||||
|
static gpu::PipelinePointer _occlusionPipeline;
|
||||||
|
static gpu::PipelinePointer _bilateralBlurPipeline;
|
||||||
|
static gpu::PipelinePointer _mipCreationPipeline;
|
||||||
|
static gpu::PipelinePointer _gatherPipeline;
|
||||||
|
static gpu::PipelinePointer _buildNormalsPipeline;
|
||||||
|
|
||||||
AmbientOcclusionFramebufferPointer _framebuffer;
|
AmbientOcclusionFramebufferPointer _framebuffer;
|
||||||
|
std::array<float, SSAO_RANDOM_SAMPLE_COUNT * SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT> _randomSamples;
|
||||||
|
int _frameId{ 0 };
|
||||||
|
bool _isJitterEnabled{ true };
|
||||||
|
|
||||||
gpu::RangeTimerPointer _gpuTimer;
|
gpu::RangeTimerPointer _gpuTimer;
|
||||||
|
|
||||||
|
@ -193,7 +256,7 @@ signals:
|
||||||
|
|
||||||
class DebugAmbientOcclusion {
|
class DebugAmbientOcclusion {
|
||||||
public:
|
public:
|
||||||
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer, AmbientOcclusionEffect::ParametersBuffer>;
|
using Inputs = render::VaryingSet4<DeferredFrameTransformPointer, DeferredFramebufferPointer, LinearDepthFramebufferPointer, AmbientOcclusionEffect::AOParametersBuffer>;
|
||||||
using Config = DebugAmbientOcclusionConfig;
|
using Config = DebugAmbientOcclusionConfig;
|
||||||
using JobModel = render::Job::ModelI<DebugAmbientOcclusion, Inputs, Config>;
|
using JobModel = render::Job::ModelI<DebugAmbientOcclusion, Inputs, Config>;
|
||||||
|
|
||||||
|
|
|
@ -220,9 +220,7 @@ static const std::string DEFAULT_DEBUG_SCATTERING_SHADER{
|
||||||
|
|
||||||
static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{
|
static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER{
|
||||||
"vec4 getFragmentColor() {"
|
"vec4 getFragmentColor() {"
|
||||||
" return vec4(vec3(texture(obscuranceMap, uv).x), 1.0);"
|
" return vec4(vec3(texture(debugTexture0, uv).x), 1.0);"
|
||||||
// When drawing color " return vec4(vec3(texture(debugTexture0, uv).xyz), 1.0);"
|
|
||||||
// when drawing normal" return vec4(normalize(texture(debugTexture0, uv).xyz * 2.0 - vec3(1.0)), 1.0);"
|
|
||||||
" }"
|
" }"
|
||||||
};
|
};
|
||||||
static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{
|
static const std::string DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER{
|
||||||
|
@ -323,6 +321,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, const std::strin
|
||||||
return DEFAULT_AMBIENT_OCCLUSION_SHADER;
|
return DEFAULT_AMBIENT_OCCLUSION_SHADER;
|
||||||
case AmbientOcclusionBlurredMode:
|
case AmbientOcclusionBlurredMode:
|
||||||
return DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER;
|
return DEFAULT_AMBIENT_OCCLUSION_BLURRED_SHADER;
|
||||||
|
case AmbientOcclusionNormalMode:
|
||||||
|
return DEFAULT_HALF_NORMAL_SHADER;
|
||||||
case VelocityMode:
|
case VelocityMode:
|
||||||
return DEFAULT_VELOCITY_SHADER;
|
return DEFAULT_VELOCITY_SHADER;
|
||||||
case CustomMode:
|
case CustomMode:
|
||||||
|
@ -470,6 +470,8 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
||||||
batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionTexture());
|
batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionTexture());
|
||||||
} else if (_mode == AmbientOcclusionBlurredMode) {
|
} else if (_mode == AmbientOcclusionBlurredMode) {
|
||||||
batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionBlurredTexture());
|
batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getOcclusionBlurredTexture());
|
||||||
|
} else if (_mode == AmbientOcclusionNormalMode) {
|
||||||
|
batch.setResourceTexture(Textures::DebugTexture0, ambientOcclusionFramebuffer->getNormalTexture());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
|
@ -91,6 +91,7 @@ protected:
|
||||||
ScatteringDebugMode,
|
ScatteringDebugMode,
|
||||||
AmbientOcclusionMode,
|
AmbientOcclusionMode,
|
||||||
AmbientOcclusionBlurredMode,
|
AmbientOcclusionBlurredMode,
|
||||||
|
AmbientOcclusionNormalMode,
|
||||||
VelocityMode,
|
VelocityMode,
|
||||||
CustomMode, // Needs to stay last
|
CustomMode, // Needs to stay last
|
||||||
|
|
||||||
|
|
|
@ -120,13 +120,22 @@ float getStereoSideHeight(int resolutionLevel) {
|
||||||
return float(int(frameTransform._pixelInfo.w) >> resolutionLevel);
|
return float(int(frameTransform._pixelInfo.w) >> resolutionLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 getSideImageSize(int resolutionLevel) {
|
vec2 getStereoSideSize(int resolutionLevel) {
|
||||||
return vec2(float(int(frameTransform._stereoInfo.y) >> resolutionLevel), float(int(frameTransform._pixelInfo.w) >> resolutionLevel));
|
return vec2(getStereoSideWidth(resolutionLevel), getStereoSideHeight(resolutionLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec4 getStereoSideInfoFromWidth(int xPos, int sideWidth) {
|
||||||
|
return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo());
|
||||||
}
|
}
|
||||||
|
|
||||||
ivec4 getStereoSideInfo(int xPos, int resolutionLevel) {
|
ivec4 getStereoSideInfo(int xPos, int resolutionLevel) {
|
||||||
int sideWidth = int(getStereoSideWidth(resolutionLevel));
|
int sideWidth = int(getStereoSideWidth(resolutionLevel));
|
||||||
return ivec4(xPos < sideWidth ? ivec2(0, 0) : ivec2(1, sideWidth), sideWidth, isStereo());
|
return getStereoSideInfoFromWidth(xPos, sideWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getStereoSide(ivec4 sideInfo) {
|
||||||
|
return sideInfo.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
float evalZeyeFromZdb(float depth) {
|
float evalZeyeFromZdb(float depth) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "SurfaceGeometryPass.h"
|
#include "SurfaceGeometryPass.h"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <MathUtils.h>
|
||||||
|
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
#include <shaders/Shaders.h>
|
#include <shaders/Shaders.h>
|
||||||
|
@ -28,19 +29,27 @@ namespace ru {
|
||||||
LinearDepthFramebuffer::LinearDepthFramebuffer() {
|
LinearDepthFramebuffer::LinearDepthFramebuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinearDepthFramebuffer::updatePrimaryDepth(const gpu::TexturePointer& depthBuffer) {
|
void LinearDepthFramebuffer::update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo) {
|
||||||
//If the depth buffer or size changed, we need to delete our FBOs
|
//If the depth buffer or size changed, we need to delete our FBOs
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
if ((_primaryDepthTexture != depthBuffer)) {
|
if (_primaryDepthTexture != depthBuffer || _normalTexture != normalTexture) {
|
||||||
_primaryDepthTexture = depthBuffer;
|
_primaryDepthTexture = depthBuffer;
|
||||||
|
_normalTexture = normalTexture;
|
||||||
reset = true;
|
reset = true;
|
||||||
}
|
}
|
||||||
if (_primaryDepthTexture) {
|
if (_primaryDepthTexture) {
|
||||||
auto newFrameSize = glm::ivec2(_primaryDepthTexture->getDimensions());
|
auto newFrameSize = glm::ivec2(_primaryDepthTexture->getDimensions());
|
||||||
if (_frameSize != newFrameSize) {
|
if (_frameSize != newFrameSize || _isStereo != isStereo) {
|
||||||
_frameSize = newFrameSize;
|
_frameSize = newFrameSize;
|
||||||
_halfFrameSize = newFrameSize >> 1;
|
_halfFrameSize = _frameSize;
|
||||||
|
if (isStereo) {
|
||||||
|
_halfFrameSize.x >>= 1;
|
||||||
|
}
|
||||||
|
_halfFrameSize >>= 1;
|
||||||
|
if (isStereo) {
|
||||||
|
_halfFrameSize.x <<= 1;
|
||||||
|
}
|
||||||
|
_isStereo = isStereo;
|
||||||
reset = true;
|
reset = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,16 +73,22 @@ void LinearDepthFramebuffer::allocate() {
|
||||||
auto height = _frameSize.y;
|
auto height = _frameSize.y;
|
||||||
|
|
||||||
// For Linear Depth:
|
// For Linear Depth:
|
||||||
_linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, gpu::Texture::SINGLE_MIP,
|
const uint16_t LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
|
||||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT));
|
// Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO
|
||||||
|
const auto depthSamplerFull = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP);
|
||||||
|
_linearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), width, height, LINEAR_DEPTH_MAX_MIP_LEVEL,
|
||||||
|
depthSamplerFull);
|
||||||
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth"));
|
_linearDepthFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("linearDepth"));
|
||||||
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
|
_linearDepthFramebuffer->setRenderBuffer(0, _linearDepthTexture);
|
||||||
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
|
_linearDepthFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, _primaryDepthTexture->getTexelFormat());
|
||||||
|
|
||||||
// For Downsampling:
|
// For Downsampling:
|
||||||
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
|
const uint16_t HALF_LINEAR_DEPTH_MAX_MIP_LEVEL = 5;
|
||||||
_halfLinearDepthTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), _halfFrameSize.x, _halfFrameSize.y, HALF_LINEAR_DEPTH_MAX_MIP_LEVEL,
|
// Point sampling of the depth, as well as the clamp to edge, are needed for the AmbientOcclusionEffect with HBAO
|
||||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT));
|
const auto depthSamplerHalf = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_POINT, gpu::Sampler::WRAP_CLAMP);
|
||||||
|
// The depth format here is half float as it increases performance in the AmbientOcclusion. But it might be needed elsewhere...
|
||||||
|
_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,
|
_halfNormalTexture = gpu::Texture::createRenderBuffer(gpu::Element::COLOR_RGBA_32, _halfFrameSize.x, _halfFrameSize.y, gpu::Texture::SINGLE_MIP,
|
||||||
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT));
|
gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT));
|
||||||
|
@ -97,6 +112,10 @@ gpu::TexturePointer LinearDepthFramebuffer::getLinearDepthTexture() {
|
||||||
return _linearDepthTexture;
|
return _linearDepthTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::TexturePointer LinearDepthFramebuffer::getNormalTexture() {
|
||||||
|
return _normalTexture;
|
||||||
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer LinearDepthFramebuffer::getDownsampleFramebuffer() {
|
gpu::FramebufferPointer LinearDepthFramebuffer::getDownsampleFramebuffer() {
|
||||||
if (!_downsampleFramebuffer) {
|
if (!_downsampleFramebuffer) {
|
||||||
allocate();
|
allocate();
|
||||||
|
@ -141,11 +160,12 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
|
||||||
if (!_linearDepthFramebuffer) {
|
if (!_linearDepthFramebuffer) {
|
||||||
_linearDepthFramebuffer = std::make_shared<LinearDepthFramebuffer>();
|
_linearDepthFramebuffer = std::make_shared<LinearDepthFramebuffer>();
|
||||||
}
|
}
|
||||||
_linearDepthFramebuffer->updatePrimaryDepth(deferredFramebuffer->getPrimaryDepthTexture());
|
|
||||||
|
|
||||||
auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture();
|
auto depthBuffer = deferredFramebuffer->getPrimaryDepthTexture();
|
||||||
auto normalTexture = deferredFramebuffer->getDeferredNormalTexture();
|
auto normalTexture = deferredFramebuffer->getDeferredNormalTexture();
|
||||||
|
|
||||||
|
_linearDepthFramebuffer->update(depthBuffer, normalTexture, args->isStereo());
|
||||||
|
|
||||||
auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer();
|
auto linearDepthFBO = _linearDepthFramebuffer->getLinearDepthFramebuffer();
|
||||||
auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture();
|
auto linearDepthTexture = _linearDepthFramebuffer->getLinearDepthTexture();
|
||||||
|
|
||||||
|
@ -167,32 +187,34 @@ void LinearDepthPass::run(const render::RenderContextPointer& renderContext, con
|
||||||
float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f;
|
float clearLinearDepth = args->getViewFrustum().getFarClip() * 2.0f;
|
||||||
|
|
||||||
gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) {
|
gpu::doInBatch("LinearDepthPass::run", args->_context, [=](gpu::Batch& batch) {
|
||||||
|
PROFILE_RANGE_BATCH(batch, "LinearDepthPass");
|
||||||
_gpuTimer->begin(batch);
|
_gpuTimer->begin(batch);
|
||||||
|
|
||||||
batch.enableStereo(false);
|
batch.enableStereo(false);
|
||||||
|
|
||||||
batch.setViewportTransform(depthViewport);
|
|
||||||
batch.setProjectionTransform(glm::mat4());
|
batch.setProjectionTransform(glm::mat4());
|
||||||
batch.resetViewTransform();
|
batch.resetViewTransform();
|
||||||
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport));
|
|
||||||
|
|
||||||
batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
|
batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, frameTransform->getFrameTransformBuffer());
|
||||||
|
|
||||||
// LinearDepth
|
// LinearDepth
|
||||||
|
batch.setViewportTransform(depthViewport);
|
||||||
batch.setFramebuffer(linearDepthFBO);
|
batch.setFramebuffer(linearDepthFBO);
|
||||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(clearLinearDepth, 0.0f, 0.0f, 0.0f));
|
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(clearLinearDepth, 0.0f, 0.0f, 0.0f));
|
||||||
batch.setPipeline(linearDepthPipeline);
|
batch.setPipeline(linearDepthPipeline);
|
||||||
|
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize(), depthViewport));
|
||||||
batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, depthBuffer);
|
batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, depthBuffer);
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||||
|
|
||||||
// Downsample
|
// Downsample
|
||||||
batch.setViewportTransform(halfViewport);
|
batch.setViewportTransform(halfViewport);
|
||||||
|
|
||||||
batch.setFramebuffer(downsampleFBO);
|
batch.setFramebuffer(downsampleFBO);
|
||||||
batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, linearDepthTexture);
|
batch.setResourceTexture(ru::Texture::SurfaceGeometryDepth, linearDepthTexture);
|
||||||
batch.setResourceTexture(ru::Texture::SurfaceGeometryNormal, normalTexture);
|
batch.setResourceTexture(ru::Texture::SurfaceGeometryNormal, normalTexture);
|
||||||
batch.setPipeline(downsamplePipeline);
|
batch.setPipeline(downsamplePipeline);
|
||||||
|
batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(_linearDepthFramebuffer->getDepthFrameSize() >> 1, halfViewport));
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||||
|
|
||||||
_gpuTimer->end(batch);
|
_gpuTimer->end(batch);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,7 +266,7 @@ const gpu::PipelinePointer& LinearDepthPass::getDownsamplePipeline(const render:
|
||||||
SurfaceGeometryFramebuffer::SurfaceGeometryFramebuffer() {
|
SurfaceGeometryFramebuffer::SurfaceGeometryFramebuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceGeometryFramebuffer::updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer) {
|
void SurfaceGeometryFramebuffer::update(const gpu::TexturePointer& linearDepthBuffer) {
|
||||||
//If the depth buffer or size changed, we need to delete our FBOs
|
//If the depth buffer or size changed, we need to delete our FBOs
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
if ((_linearDepthTexture != linearDepthBuffer)) {
|
if ((_linearDepthTexture != linearDepthBuffer)) {
|
||||||
|
@ -411,7 +433,7 @@ void SurfaceGeometryPass::run(const render::RenderContextPointer& renderContext,
|
||||||
if (!_surfaceGeometryFramebuffer) {
|
if (!_surfaceGeometryFramebuffer) {
|
||||||
_surfaceGeometryFramebuffer = std::make_shared<SurfaceGeometryFramebuffer>();
|
_surfaceGeometryFramebuffer = std::make_shared<SurfaceGeometryFramebuffer>();
|
||||||
}
|
}
|
||||||
_surfaceGeometryFramebuffer->updateLinearDepth(linearDepthTexture);
|
_surfaceGeometryFramebuffer->update(linearDepthTexture);
|
||||||
|
|
||||||
auto curvatureFramebuffer = _surfaceGeometryFramebuffer->getCurvatureFramebuffer();
|
auto curvatureFramebuffer = _surfaceGeometryFramebuffer->getCurvatureFramebuffer();
|
||||||
auto curvatureTexture = _surfaceGeometryFramebuffer->getCurvatureTexture();
|
auto curvatureTexture = _surfaceGeometryFramebuffer->getCurvatureTexture();
|
||||||
|
|
|
@ -28,17 +28,17 @@ public:
|
||||||
|
|
||||||
gpu::FramebufferPointer getLinearDepthFramebuffer();
|
gpu::FramebufferPointer getLinearDepthFramebuffer();
|
||||||
gpu::TexturePointer getLinearDepthTexture();
|
gpu::TexturePointer getLinearDepthTexture();
|
||||||
|
gpu::TexturePointer getNormalTexture();
|
||||||
|
|
||||||
gpu::FramebufferPointer getDownsampleFramebuffer();
|
gpu::FramebufferPointer getDownsampleFramebuffer();
|
||||||
gpu::TexturePointer getHalfLinearDepthTexture();
|
gpu::TexturePointer getHalfLinearDepthTexture();
|
||||||
gpu::TexturePointer getHalfNormalTexture();
|
gpu::TexturePointer getHalfNormalTexture();
|
||||||
|
|
||||||
// Update the depth buffer which will drive the allocation of all the other resources according to its size.
|
// Update the depth buffer which will drive the allocation of all the other resources according to its size.
|
||||||
void updatePrimaryDepth(const gpu::TexturePointer& depthBuffer);
|
void update(const gpu::TexturePointer& depthBuffer, const gpu::TexturePointer& normalTexture, bool isStereo);
|
||||||
gpu::TexturePointer getPrimaryDepthTexture();
|
|
||||||
const glm::ivec2& getDepthFrameSize() const { return _frameSize; }
|
const glm::ivec2& getDepthFrameSize() const { return _frameSize; }
|
||||||
|
|
||||||
void setResolutionLevel(int level);
|
void setResolutionLevel(int level) { _resolutionLevel = std::max(0, level); }
|
||||||
int getResolutionLevel() const { return _resolutionLevel; }
|
int getResolutionLevel() const { return _resolutionLevel; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -49,6 +49,7 @@ protected:
|
||||||
|
|
||||||
gpu::FramebufferPointer _linearDepthFramebuffer;
|
gpu::FramebufferPointer _linearDepthFramebuffer;
|
||||||
gpu::TexturePointer _linearDepthTexture;
|
gpu::TexturePointer _linearDepthTexture;
|
||||||
|
gpu::TexturePointer _normalTexture;
|
||||||
|
|
||||||
gpu::FramebufferPointer _downsampleFramebuffer;
|
gpu::FramebufferPointer _downsampleFramebuffer;
|
||||||
gpu::TexturePointer _halfLinearDepthTexture;
|
gpu::TexturePointer _halfLinearDepthTexture;
|
||||||
|
@ -58,6 +59,7 @@ protected:
|
||||||
glm::ivec2 _frameSize;
|
glm::ivec2 _frameSize;
|
||||||
glm::ivec2 _halfFrameSize;
|
glm::ivec2 _halfFrameSize;
|
||||||
int _resolutionLevel{ 0 };
|
int _resolutionLevel{ 0 };
|
||||||
|
bool _isStereo{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
using LinearDepthFramebufferPointer = std::shared_ptr<LinearDepthFramebuffer>;
|
using LinearDepthFramebufferPointer = std::shared_ptr<LinearDepthFramebuffer>;
|
||||||
|
@ -107,7 +109,7 @@ public:
|
||||||
gpu::TexturePointer getBlurringTexture();
|
gpu::TexturePointer getBlurringTexture();
|
||||||
|
|
||||||
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
// Update the source framebuffer size which will drive the allocation of all the other resources.
|
||||||
void updateLinearDepth(const gpu::TexturePointer& linearDepthBuffer);
|
void update(const gpu::TexturePointer& linearDepthBuffer);
|
||||||
gpu::TexturePointer getLinearDepthTexture();
|
gpu::TexturePointer getLinearDepthTexture();
|
||||||
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
const glm::ivec2& getSourceFrameSize() const { return _frameSize; }
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,10 @@
|
||||||
// Ambient occlusion
|
// Ambient occlusion
|
||||||
#define RENDER_UTILS_BUFFER_SSAO_PARAMS 2
|
#define RENDER_UTILS_BUFFER_SSAO_PARAMS 2
|
||||||
#define RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS 3
|
#define RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS 3
|
||||||
#define RENDER_UTILS_TEXTURE_SSAO_PYRAMID 1
|
#define RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS 4
|
||||||
|
#define RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS 5
|
||||||
|
#define RENDER_UTILS_TEXTURE_SSAO_DEPTH 1
|
||||||
|
#define RENDER_UTILS_TEXTURE_SSAO_NORMAL 2
|
||||||
#define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0
|
#define RENDER_UTILS_TEXTURE_SSAO_OCCLUSION 0
|
||||||
|
|
||||||
// Temporal anti-aliasing
|
// Temporal anti-aliasing
|
||||||
|
@ -120,7 +123,6 @@
|
||||||
#define RENDER_UTILS_UNIFORM_TEXT_COLOR 0
|
#define RENDER_UTILS_UNIFORM_TEXT_COLOR 0
|
||||||
#define RENDER_UTILS_UNIFORM_TEXT_OUTLINE 1
|
#define RENDER_UTILS_UNIFORM_TEXT_OUTLINE 1
|
||||||
|
|
||||||
|
|
||||||
// Debugging
|
// Debugging
|
||||||
#define RENDER_UTILS_BUFFER_DEBUG_SKYBOX 5
|
#define RENDER_UTILS_BUFFER_DEBUG_SKYBOX 5
|
||||||
#define RENDER_UTILS_DEBUG_TEXTURE0 11
|
#define RENDER_UTILS_DEBUG_TEXTURE0 11
|
||||||
|
@ -144,7 +146,9 @@ enum Buffer {
|
||||||
LightClusterContent = RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT,
|
LightClusterContent = RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT,
|
||||||
SsscParams = RENDER_UTILS_BUFFER_SSSC_PARAMS,
|
SsscParams = RENDER_UTILS_BUFFER_SSSC_PARAMS,
|
||||||
SsaoParams = RENDER_UTILS_BUFFER_SSAO_PARAMS,
|
SsaoParams = RENDER_UTILS_BUFFER_SSAO_PARAMS,
|
||||||
|
SsaoFrameParams = RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS,
|
||||||
SsaoDebugParams = RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS,
|
SsaoDebugParams = RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS,
|
||||||
|
SsaoBlurParams = RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS,
|
||||||
LightIndex = RENDER_UTILS_BUFFER_LIGHT_INDEX,
|
LightIndex = RENDER_UTILS_BUFFER_LIGHT_INDEX,
|
||||||
TaaParams = RENDER_UTILS_BUFFER_TAA_PARAMS,
|
TaaParams = RENDER_UTILS_BUFFER_TAA_PARAMS,
|
||||||
HighlightParams = RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS,
|
HighlightParams = RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS,
|
||||||
|
@ -183,7 +187,8 @@ enum Texture {
|
||||||
TaaDepth = RENDER_UTILS_TEXTURE_TAA_DEPTH,
|
TaaDepth = RENDER_UTILS_TEXTURE_TAA_DEPTH,
|
||||||
TaaNext = RENDER_UTILS_TEXTURE_TAA_NEXT,
|
TaaNext = RENDER_UTILS_TEXTURE_TAA_NEXT,
|
||||||
SsaoOcclusion = RENDER_UTILS_TEXTURE_SSAO_OCCLUSION,
|
SsaoOcclusion = RENDER_UTILS_TEXTURE_SSAO_OCCLUSION,
|
||||||
SsaoPyramid = RENDER_UTILS_TEXTURE_SSAO_PYRAMID,
|
SsaoDepth = RENDER_UTILS_TEXTURE_SSAO_DEPTH,
|
||||||
|
SsaoNormal = RENDER_UTILS_TEXTURE_SSAO_NORMAL,
|
||||||
HighlightSceneDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH,
|
HighlightSceneDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH,
|
||||||
HighlightDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH,
|
HighlightDepth = RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH,
|
||||||
SurfaceGeometryDepth = RENDER_UTILS_TEXTURE_SG_DEPTH,
|
SurfaceGeometryDepth = RENDER_UTILS_TEXTURE_SG_DEPTH,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -12,52 +12,94 @@
|
||||||
<@def SSAO_SLH@>
|
<@def SSAO_SLH@>
|
||||||
|
|
||||||
<@include render-utils/ShaderConstants.h@>
|
<@include render-utils/ShaderConstants.h@>
|
||||||
|
<@include ssao_shared.h@>
|
||||||
|
|
||||||
<@func declarePackOcclusionDepth()@>
|
<@func declarePackOcclusionDepth()@>
|
||||||
|
|
||||||
const float FAR_PLANE_Z = -300.0;
|
float CSZToDepthKey(float z) {
|
||||||
|
return clamp(z * (-1.0 / SSAO_DEPTH_KEY_SCALE), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
float CSZToDephtKey(float z) {
|
vec4 packOcclusionOutput(float occlusion, float depth, vec3 eyeNormal) {
|
||||||
return clamp(z * (1.0 / FAR_PLANE_Z), 0.0, 1.0);
|
depth = CSZToDepthKey(depth);
|
||||||
}
|
#if SSAO_BILATERAL_BLUR_USE_NORMAL
|
||||||
vec3 packOcclusionDepth(float occlusion, float depth) {
|
return vec4(occlusion, depth, eyeNormal.xy / eyeNormal.z);
|
||||||
|
#else
|
||||||
// Round to the nearest 1/256.0
|
// Round to the nearest 1/256.0
|
||||||
float temp = floor(depth * 256.0);
|
depth *= 256.0;
|
||||||
return vec3(occlusion, temp * (1.0 / 256.0), depth * 256.0 - temp);
|
float temp = floor(depth);
|
||||||
|
return vec4(occlusion, temp * (1.0 / 256.0), depth - temp, 0.0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
vec2 unpackOcclusionDepth(vec3 raw) {
|
|
||||||
float z = raw.y * (256.0 / 257.0) + raw.z * (1.0 / 257.0);
|
struct UnpackedOcclusion {
|
||||||
return vec2(raw.x, z);
|
vec3 normal;
|
||||||
|
float depth;
|
||||||
|
float occlusion;
|
||||||
|
};
|
||||||
|
|
||||||
|
void unpackOcclusionOutput(vec4 raw, out UnpackedOcclusion result) {
|
||||||
|
result.occlusion = raw.x;
|
||||||
|
#if SSAO_BILATERAL_BLUR_USE_NORMAL
|
||||||
|
result.depth = raw.y;
|
||||||
|
result.normal = normalize(vec3(raw.zw, 1.0));
|
||||||
|
#else
|
||||||
|
result.depth = (raw.y + raw.z / 256.0);
|
||||||
|
result.normal = vec3(0.0, 0.0, 1.0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float unpackOcclusion(vec4 raw) {
|
||||||
|
return raw.x;
|
||||||
|
}
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
<@func declareAmbientOcclusion()@>
|
<@func declareAmbientOcclusion()@>
|
||||||
<@include DeferredTransform.slh@>
|
<@include DeferredTransform.slh@>
|
||||||
<$declareDeferredFrameTransform()$>
|
<$declareDeferredFrameTransform()$>
|
||||||
|
|
||||||
struct AmbientOcclusionParams {
|
|
||||||
vec4 _resolutionInfo;
|
|
||||||
vec4 _radiusInfo;
|
|
||||||
vec4 _ditheringInfo;
|
|
||||||
vec4 _sampleInfo;
|
|
||||||
vec4 _blurInfo;
|
|
||||||
float _gaussianCoefs[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer {
|
LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer {
|
||||||
AmbientOcclusionParams params;
|
AmbientOcclusionParams params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_FRAME_PARAMS) uniform ambientOcclusionFrameParamsBuffer {
|
||||||
|
AmbientOcclusionFrameParams frameParams;
|
||||||
|
};
|
||||||
|
|
||||||
float getPerspectiveScale() {
|
float getPerspectiveScale() {
|
||||||
|
|
||||||
return (params._resolutionInfo.z);
|
return (params._resolutionInfo.z);
|
||||||
}
|
}
|
||||||
int getResolutionLevel() {
|
int getResolutionLevel() {
|
||||||
|
|
||||||
return int(params._resolutionInfo.x);
|
return int(params._resolutionInfo.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isHorizonBased() {
|
||||||
|
return params._resolutionInfo.y!=0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getNormalsSideSize() {
|
||||||
|
return params._sideSizes[0].xy;
|
||||||
|
}
|
||||||
|
int getNormalsResolutionLevel() {
|
||||||
|
return int(params._sideSizes[0].z);
|
||||||
|
}
|
||||||
|
int getDepthResolutionLevel() {
|
||||||
|
return int(params._sideSizes[0].w);
|
||||||
|
}
|
||||||
|
vec2 getOcclusionSideSize() {
|
||||||
|
return params._sideSizes[1].xy;
|
||||||
|
}
|
||||||
|
vec2 getOcclusionSplitSideSize() {
|
||||||
|
return params._sideSizes[1].zw;
|
||||||
|
}
|
||||||
|
|
||||||
|
ivec2 getWidthHeightRoundUp(int resolutionLevel) {
|
||||||
|
ivec2 fullRes = ivec2(getWidthHeight(0));
|
||||||
|
int resolutionDivisor = 1 << resolutionLevel;
|
||||||
|
return (fullRes + resolutionDivisor - 1) / resolutionDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
float getRadius() {
|
float getRadius() {
|
||||||
return params._radiusInfo.x;
|
return params._radiusInfo.x;
|
||||||
}
|
}
|
||||||
|
@ -65,24 +107,35 @@ float getRadius2() {
|
||||||
return params._radiusInfo.y;
|
return params._radiusInfo.y;
|
||||||
}
|
}
|
||||||
float getInvRadius6() {
|
float getInvRadius6() {
|
||||||
|
return mix(params._radiusInfo.z, 1.0, isHorizonBased());
|
||||||
|
}
|
||||||
|
float getInvRadius2() {
|
||||||
return params._radiusInfo.z;
|
return params._radiusInfo.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getObscuranceScaling() {
|
float getObscuranceScaling() {
|
||||||
return params._radiusInfo.z * params._radiusInfo.w;
|
return getInvRadius6() * params._radiusInfo.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
float isDitheringEnabled() {
|
float isDitheringEnabled() {
|
||||||
return params._ditheringInfo.x;
|
return params._ditheringInfo.x;
|
||||||
}
|
}
|
||||||
float getFrameDithering() {
|
|
||||||
return params._ditheringInfo.y;
|
|
||||||
}
|
|
||||||
float isBorderingEnabled() {
|
float isBorderingEnabled() {
|
||||||
return params._ditheringInfo.w;
|
return params._ditheringInfo.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getFalloffBias() {
|
float getFalloffCosAngle() {
|
||||||
return params._ditheringInfo.z;
|
return params._falloffInfo.x;
|
||||||
|
}
|
||||||
|
float getFalloffCosAngleScale() {
|
||||||
|
return params._falloffInfo.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getFalloffSinAngle() {
|
||||||
|
return params._falloffInfo.z;
|
||||||
|
}
|
||||||
|
float getFalloffSinAngleScale() {
|
||||||
|
return params._falloffInfo.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getNumSamples() {
|
float getNumSamples() {
|
||||||
|
@ -99,37 +152,6 @@ int doFetchMips() {
|
||||||
return int(params._sampleInfo.w);
|
return int(params._sampleInfo.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getBlurEdgeSharpness() {
|
|
||||||
return params._blurInfo.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONSTANT_GAUSSIAN
|
|
||||||
const int BLUR_RADIUS = 4;
|
|
||||||
const float gaussian[BLUR_RADIUS + 1] =
|
|
||||||
// KEEP this dead code for eventual performance improvment
|
|
||||||
// float[](0.356642, 0.239400, 0.072410, 0.009869);
|
|
||||||
// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
|
|
||||||
float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
|
|
||||||
//float[](0.197413, 0.17467, 0.12098,0.065591,0.040059);
|
|
||||||
// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
|
|
||||||
|
|
||||||
int getBlurRadius() {
|
|
||||||
return BLUR_RADIUS;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getBlurCoef(int c) {
|
|
||||||
return gaussian[c];
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int getBlurRadius() {
|
|
||||||
return int(params._blurInfo.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getBlurCoef(int c) {
|
|
||||||
return params._gaussianCoefs[c];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
<@func declareSamplingDisk()@>
|
<@func declareSamplingDisk()@>
|
||||||
|
@ -139,43 +161,57 @@ float getAngleDitheringWorldPos(in vec3 pixelWorldPos) {
|
||||||
|
|
||||||
ivec3 pixelPos = ivec3(worldPosFract * 256.0);
|
ivec3 pixelPos = ivec3(worldPosFract * 256.0);
|
||||||
|
|
||||||
return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10) + getFrameDithering();
|
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) {
|
float getAngleDithering(in ivec2 pixelPos) {
|
||||||
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
|
return getAngleDitheringSplit();
|
||||||
|
#else
|
||||||
// Hash function used in the AlchemyAO paper
|
// Hash function used in the AlchemyAO paper
|
||||||
return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10) + getFrameDithering();
|
return getAngleDitheringPixelPos(pixelPos);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
float evalDiskRadius(float Zeye, vec2 imageSize) {
|
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
|
// Choose the screen-space sample radius
|
||||||
// proportional to the projected area of the sphere
|
// proportional to the projected area of the sphere
|
||||||
float ssDiskRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale();
|
float diskPixelRadius = -( getProjScale(getResolutionLevel()) * getRadius() / Zeye ) * getPerspectiveScale();
|
||||||
|
|
||||||
// clamp the disk to fit in the image otherwise too many unknown
|
// clamp the disk to fit in the image otherwise too many unknown
|
||||||
ssDiskRadius = min(ssDiskRadius, imageSize.y * 0.5);
|
diskPixelRadius = min(diskPixelRadius, sideImageSize.y * 0.5);
|
||||||
|
|
||||||
return ssDiskRadius;
|
return diskPixelRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float TWO_PI = 6.28;
|
const float PI = 3.1415926;
|
||||||
|
const float TWO_PI = 6.2831852;
|
||||||
|
|
||||||
vec3 getUnitTapLocation(int sampleNumber, float spinAngle){
|
vec3 getUnitTapLocation(int sampleNumber, float spiralTurns, float spinAngle, float angleRange){
|
||||||
// Radius relative to ssR
|
// Radius relative to ssR
|
||||||
float alpha = (float(sampleNumber) + 0.5) * getInvNumSamples();
|
float alpha = float(sampleNumber) * getInvNumSamples();
|
||||||
float angle = alpha * (getNumSpiralTurns() * TWO_PI) + spinAngle;
|
float angle = alpha * (spiralTurns * angleRange) + spinAngle;
|
||||||
return vec3(cos(angle), sin(angle), alpha);
|
return vec3(cos(angle), sin(angle), alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 getTapLocation(int sampleNumber, float spinAngle, float outerRadius) {
|
vec3 getTapLocationSSAO(int sampleNumber, float spinAngle, float outerRadius) {
|
||||||
vec3 tap = getUnitTapLocation(sampleNumber, spinAngle);
|
vec3 tap = getUnitTapLocation(sampleNumber, getNumSpiralTurns(), spinAngle, TWO_PI);
|
||||||
tap.xy *= tap.z;
|
tap.xy *= tap.z;
|
||||||
tap *= outerRadius;
|
tap *= outerRadius;
|
||||||
return tap;
|
return tap;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 imageSize) {
|
vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRadius, vec2 pixelPos, vec2 sideImageSize) {
|
||||||
vec3 tap = getTapLocation(sampleNumber, spinAngle, outerRadius);
|
vec3 tap = getTapLocationSSAO(sampleNumber, spinAngle, outerRadius);
|
||||||
vec2 tapPos = pixelPos + tap.xy;
|
vec2 tapPos = pixelPos + tap.xy;
|
||||||
|
|
||||||
if (!(isBorderingEnabled() > 0.0)) {
|
if (!(isBorderingEnabled() > 0.0)) {
|
||||||
|
@ -186,36 +222,19 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius,
|
||||||
if ((tapPos.x < 0.5)) {
|
if ((tapPos.x < 0.5)) {
|
||||||
tapPos.x = -tapPos.x;
|
tapPos.x = -tapPos.x;
|
||||||
redoTap = true;
|
redoTap = true;
|
||||||
} else if ((tapPos.x > imageSize.x - 0.5)) {
|
} else if ((tapPos.x > sideImageSize.x - 0.5)) {
|
||||||
tapPos.x -= (imageSize.x - tapPos.x);
|
tapPos.x -= (sideImageSize.x - tapPos.x);
|
||||||
redoTap = true;
|
redoTap = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tapPos.y < 0.5)) {
|
if ((tapPos.y < 0.5)) {
|
||||||
tapPos.y = -tapPos.y;
|
tapPos.y = -tapPos.y;
|
||||||
redoTap = true;
|
redoTap = true;
|
||||||
} else if ((tapPos.y > imageSize.y - 0.5)) {
|
} else if ((tapPos.y > sideImageSize.y - 0.5)) {
|
||||||
tapPos.y -= (imageSize.y - tapPos.y);
|
tapPos.y -= (sideImageSize.y - tapPos.y);
|
||||||
redoTap = true;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if ((tapPos.x < 0.5)) {
|
|
||||||
tapPos.x = 0.5;
|
|
||||||
redoTap = true;
|
|
||||||
} else if ((tapPos.x > imageSize.x - 0.5)) {
|
|
||||||
tapPos.x = imageSize.x - 0.5;
|
|
||||||
redoTap = true;
|
redoTap = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tapPos.y < 0.5)) {
|
|
||||||
tapPos.y = 0.5;
|
|
||||||
redoTap = true;
|
|
||||||
} else if ((tapPos.y > imageSize.y - 0.5)) {
|
|
||||||
tapPos.y = imageSize.y - 0.5;
|
|
||||||
redoTap = true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (redoTap) {
|
if (redoTap) {
|
||||||
tap.xy = tapPos - pixelPos;
|
tap.xy = tapPos - pixelPos;
|
||||||
tap.z = length(tap.xy);
|
tap.z = length(tap.xy);
|
||||||
|
@ -230,156 +249,341 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius,
|
||||||
|
|
||||||
<@func declareFetchDepthPyramidMap()@>
|
<@func declareFetchDepthPyramidMap()@>
|
||||||
|
|
||||||
|
|
||||||
// the depth pyramid texture
|
// the depth pyramid texture
|
||||||
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap;
|
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_DEPTH) uniform sampler2D depthPyramidTex;
|
||||||
|
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_NORMAL) uniform sampler2D normalTex;
|
||||||
|
|
||||||
float getZEye(ivec2 pixel, int level) {
|
vec2 getFramebufferUVFromSideUV(ivec4 side, vec2 uv) {
|
||||||
return -texelFetch(pyramidMap, pixel, level).x;
|
return mix(uv, vec2((uv.x + float(getStereoSide(side))) * 0.5, uv.y), float(isStereo()));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getSideUVFromFramebufferUV(ivec4 side, vec2 uv) {
|
||||||
|
return mix(uv, vec2(uv.x * 2.0 - float(getStereoSide(side)), uv.y), float(isStereo()));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getDepthTextureSize(int level) {
|
||||||
|
return vec2(textureSize(depthPyramidTex, level));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getDepthTextureSideSize(int level) {
|
||||||
|
ivec2 size = textureSize(depthPyramidTex, level);
|
||||||
|
size.x >>= int(isStereo()) & 1;
|
||||||
|
return vec2(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getStereoSideSizeRoundUp(int resolutionLevel) {
|
||||||
|
ivec2 fullRes = ivec2(getStereoSideSize(0));
|
||||||
|
int resolutionDivisor = 1 << resolutionLevel;
|
||||||
|
return vec2((fullRes + resolutionDivisor - 1) / resolutionDivisor);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getZEyeAtUV(vec2 texCoord, float level) {
|
||||||
|
return -textureLod(depthPyramidTex, texCoord, level).x;
|
||||||
|
}
|
||||||
|
|
||||||
|
<@func getZEyeAtUVOffset(texCoord, level, texelOffset)@>
|
||||||
|
-textureLodOffset(depthPyramidTex, <$texCoord$>, <$level$>, <$texelOffset$>).x;
|
||||||
|
<@endfunc@>
|
||||||
|
|
||||||
|
float getZEyeAtUV(ivec4 side, vec2 texCoord, float level) {
|
||||||
|
texCoord = getFramebufferUVFromSideUV(side, texCoord);
|
||||||
|
return getZEyeAtUV(texCoord, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 packNormal(vec3 normal) {
|
||||||
|
vec3 absNormal = abs(normal);
|
||||||
|
return 0.5 + normal * 0.5 / max(absNormal.x, max(absNormal.y, absNormal.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 unpackNormal(vec3 packedNormal) {
|
||||||
|
return normalize(packedNormal*2.0 - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getNormalEyeAtUV(vec2 texCoord, float level) {
|
||||||
|
return unpackNormal(textureLod(normalTex, texCoord, level).xyz);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getNormalEyeAtUV(ivec4 side, vec2 texCoord, float level) {
|
||||||
|
texCoord = getFramebufferUVFromSideUV(side, texCoord);
|
||||||
|
return getNormalEyeAtUV(texCoord, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 snapToTexel(vec2 uv, vec2 pixelSize) {
|
||||||
|
return (floor(uv * pixelSize - 0.5) + 0.5) / pixelSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int LOG_MAX_OFFSET = 3;
|
|
||||||
const int MAX_MIP_LEVEL = 5;
|
|
||||||
int evalMipFromRadius(float radius) {
|
int evalMipFromRadius(float radius) {
|
||||||
// mipLevel = floor(log(ssR / MAX_OFFSET));
|
const int LOG_MAX_OFFSET = 2;
|
||||||
|
const int MAX_MIP_LEVEL = 5;
|
||||||
return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
|
return clamp(findMSB(int(radius)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec2 fetchTap(ivec4 side, vec2 tapUV, float tapRadius) {
|
||||||
|
int mipLevel = evalMipFromRadius(tapRadius * float(doFetchMips()));
|
||||||
|
|
||||||
vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
|
vec2 fetchUV = clamp(tapUV, vec2(0), vec2(1));
|
||||||
ivec2 ssP = ivec2(tap.xy) + ssC;
|
fetchUV = getFramebufferUVFromSideUV(side, fetchUV);
|
||||||
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
|
|
||||||
|
|
||||||
|
vec2 P;
|
||||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
|
P.x = float(mipLevel);
|
||||||
|
P.y = -textureLod(depthPyramidTex, fetchUV, P.x).x;
|
||||||
vec2 fetchUV = vec2(tapUV.x + float(side.w) * 0.5 * (float(side.x) - tapUV.x), tapUV.y);
|
return P;
|
||||||
|
|
||||||
vec3 P;
|
|
||||||
P.xy = tapUV;
|
|
||||||
P.z = -texture(pyramidMap, fetchUV).x;
|
|
||||||
|
|
||||||
return P;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) {
|
vec3 buildPosition(ivec4 side, vec2 fragUVPos) {
|
||||||
int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips()));
|
float Zeye = getZEyeAtUV(side, fragUVPos, 0.0);
|
||||||
|
return evalEyePositionFromZeye(side.x, Zeye, fragUVPos);
|
||||||
ivec2 ssP = ivec2(tap.xy) + ssC;
|
|
||||||
ivec2 ssPFull = ivec2(ssP.x + side.y, ssP.y);
|
|
||||||
|
|
||||||
// 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 mipSize = textureSize(pyramidMap, mipLevel);
|
|
||||||
ivec2 mipSize = max(ivec2(imageSize) >> mipLevel, ivec2(1));
|
|
||||||
|
|
||||||
ivec2 mipP = clamp(ssPFull >> mipLevel, ivec2(0), mipSize - ivec2(1));
|
|
||||||
|
|
||||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize;
|
|
||||||
vec2 fetchUV = vec2(tapUV.x + float(side.w) * 0.5 * (float(side.x) - tapUV.x), tapUV.y);
|
|
||||||
// vec2 tapUV = (vec2(mipP) + vec2(0.5)) / vec2(mipSize);
|
|
||||||
|
|
||||||
vec3 P;
|
|
||||||
P.xy = tapUV;
|
|
||||||
// P.z = -texelFetch(pyramidMap, mipP, mipLevel).x;
|
|
||||||
P.z = -textureLod(pyramidMap, fetchUV, float(mipLevel)).x;
|
|
||||||
|
|
||||||
return P;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<@func buildPositionOffset(side, fragUVPos, sideFragUVPos, texelOffset, deltaUV, position)@>
|
||||||
|
{
|
||||||
|
float Zeye = <$getZEyeAtUVOffset($sideFragUVPos$, 0.0, $texelOffset$)$>
|
||||||
|
<$position$> = evalEyePositionFromZeye(<$side$>.x, Zeye, <$fragUVPos$> + vec2(<$texelOffset$>)*<$deltaUV$>);
|
||||||
|
}
|
||||||
|
<@endfunc@>
|
||||||
|
|
||||||
|
vec3 getMinDelta(vec3 centralPoint, vec3 offsetPointPos, vec3 offsetPointNeg) {
|
||||||
|
vec3 delta0 = offsetPointPos - centralPoint;
|
||||||
|
vec3 delta1 = centralPoint - offsetPointNeg;
|
||||||
|
float sqrLength0 = dot(delta0, delta0);
|
||||||
|
float sqrLength1 = dot(delta1, delta1);
|
||||||
|
|
||||||
|
return mix(delta1, delta0, float(sqrLength0 < sqrLength1));
|
||||||
|
}
|
||||||
|
|
||||||
|
const ivec2 UV_RIGHT = ivec2(1,0);
|
||||||
|
const ivec2 UV_LEFT = ivec2(-1,0);
|
||||||
|
const ivec2 UV_TOP = ivec2(0,1);
|
||||||
|
const ivec2 UV_BOTTOM = ivec2(0,-1);
|
||||||
|
|
||||||
|
vec3 buildNormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec2 deltaDepthUV) {
|
||||||
|
vec2 fullUVPos = getFramebufferUVFromSideUV(side, fragUVPos);
|
||||||
|
|
||||||
|
vec3 fragPositionDxPos;
|
||||||
|
vec3 fragPositionDxNeg;
|
||||||
|
vec3 fragPositionDyPos;
|
||||||
|
vec3 fragPositionDyNeg;
|
||||||
|
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$>
|
||||||
|
|
||||||
|
vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
|
||||||
|
vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);
|
||||||
|
|
||||||
|
return normalize( cross(fragDeltaDx, fragDeltaDy) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildTangentBinormal(ivec4 side, vec2 fragUVPos, vec3 fragPosition, vec3 fragNormal, vec2 deltaDepthUV,
|
||||||
|
out vec3 fragTangent, out vec3 fragBinormal) {
|
||||||
|
vec2 fullUVPos = getFramebufferUVFromSideUV(side, fragUVPos);
|
||||||
|
|
||||||
|
vec3 fragPositionDxPos;
|
||||||
|
vec3 fragPositionDxNeg;
|
||||||
|
vec3 fragPositionDyPos;
|
||||||
|
vec3 fragPositionDyNeg;
|
||||||
|
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_RIGHT, deltaDepthUV, fragPositionDxPos)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_LEFT, deltaDepthUV, fragPositionDxNeg)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_TOP, deltaDepthUV, fragPositionDyPos)$>
|
||||||
|
<$buildPositionOffset(side, fragUVPos, fullUVPos, UV_BOTTOM, deltaDepthUV, fragPositionDyNeg)$>
|
||||||
|
|
||||||
|
vec3 fragDeltaDx = getMinDelta(fragPosition, fragPositionDxPos, fragPositionDxNeg);
|
||||||
|
vec3 fragDeltaDy = getMinDelta(fragPosition, fragPositionDyPos, fragPositionDyNeg);
|
||||||
|
|
||||||
|
//fragTangent = normalize( cross(fragDeltaDy, fragNormal) );
|
||||||
|
//fragBinormal = normalize( cross(fragNormal, fragDeltaDx) );
|
||||||
|
|
||||||
|
fragTangent = fragDeltaDx;
|
||||||
|
fragBinormal = fragDeltaDy;
|
||||||
|
}
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
<@func declareEvalObscurance()@>
|
<@func declareEvalObscurance()@>
|
||||||
|
|
||||||
float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) {
|
struct TBNFrame {
|
||||||
vec3 v = Q - C;
|
vec3 tangent;
|
||||||
float vv = dot(v, v);
|
vec3 binormal;
|
||||||
float vn = dot(v, n_C);
|
vec3 normal;
|
||||||
|
};
|
||||||
|
|
||||||
// Fall off function as recommended in SAO paper
|
vec3 fastAcos(vec3 x) {
|
||||||
|
// [Eberly2014] GPGPU Programming for Games and Science
|
||||||
|
vec3 absX = abs(x);
|
||||||
|
vec3 res = absX * (-0.156583) + vec3(PI / 2.0);
|
||||||
|
res *= sqrt(vec3(1.0) - absX);
|
||||||
|
return mix(res, vec3(PI) - res, greaterThanEqual(x, vec3(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
float evalVisibilitySSAO(in vec3 centerPosition, in vec3 centerNormal, in vec3 tapPosition) {
|
||||||
|
vec3 v = tapPosition - centerPosition;
|
||||||
|
float vv = dot(v, v);
|
||||||
|
float vn = dot(v, centerNormal);
|
||||||
|
|
||||||
|
// Falloff function as recommended in SSAO paper
|
||||||
const float epsilon = 0.01;
|
const float epsilon = 0.01;
|
||||||
float f = max(getRadius2() - vv, 0.0);
|
float f = max(getRadius2() - vv, 0.0);
|
||||||
return f * f * f * max((vn - getFalloffBias()) / (epsilon + vv), 0.0);
|
return f * f * f * max((vn - getFalloffCosAngle()) / (epsilon + vv), 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HBAO_USE_COS_ANGLE 1
|
||||||
|
#define HBAO_USE_OVERHANG_HACK 0
|
||||||
|
|
||||||
|
float computeWeightForHorizon(float horizonLimit, float distanceSquared) {
|
||||||
|
return max(0.0, 1.0 - distanceSquared * getInvRadius2());
|
||||||
|
}
|
||||||
|
|
||||||
|
float computeWeightedHorizon(float horizonLimit, float distanceSquared) {
|
||||||
|
float radiusFalloff = computeWeightForHorizon(horizonLimit, distanceSquared);
|
||||||
|
|
||||||
|
#if !HBAO_USE_COS_ANGLE
|
||||||
|
horizonLimit = getFalloffSinAngle() - horizonLimit;
|
||||||
|
#endif
|
||||||
|
horizonLimit *= radiusFalloff;
|
||||||
|
#if !HBAO_USE_COS_ANGLE
|
||||||
|
horizonLimit = getFalloffSinAngle() - horizonLimit;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return horizonLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
<@func computeHorizon()@>
|
||||||
|
if (tapUVPos.x<0.0 || tapUVPos.y<0.0 || tapUVPos.x>=1.0 || tapUVPos.y>=1.0) {
|
||||||
|
// Early exit because we've hit the borders of the frame
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vec2 tapMipZ = fetchTap(side, tapUVPos, radius);
|
||||||
|
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUVPos);
|
||||||
|
vec3 deltaVec = tapPositionES - fragPositionES;
|
||||||
|
float distanceSquared = dot(deltaVec, deltaVec);
|
||||||
|
float deltaDotNormal = dot(deltaVec, fragFrameES.normal);
|
||||||
|
#if HBAO_USE_COS_ANGLE
|
||||||
|
float tapHorizonLimit = deltaDotNormal;
|
||||||
|
#else
|
||||||
|
float tapHorizonLimit = dot(deltaVec, fragFrameES.tangent);
|
||||||
|
#endif
|
||||||
|
tapHorizonLimit *= inversesqrt(distanceSquared);
|
||||||
|
|
||||||
|
if (distanceSquared < getRadius2() && deltaDotNormal>0.0) {
|
||||||
|
#if HBAO_USE_COS_ANGLE
|
||||||
|
float weight = computeWeightForHorizon(tapHorizonLimit, distanceSquared);
|
||||||
|
if (tapHorizonLimit > horizonLimit) {
|
||||||
|
occlusion += weight * (tapHorizonLimit - horizonLimit);
|
||||||
|
horizonLimit = tapHorizonLimit;
|
||||||
|
}
|
||||||
|
#if HBAO_USE_OVERHANG_HACK
|
||||||
|
else if (dot(deltaVec, fragFrameES.tangent) < 0.0) {
|
||||||
|
// This is a hack to try to handle the case where the occlusion angle is
|
||||||
|
// greater than 90°
|
||||||
|
occlusion = mix(occlusion, (occlusion+1.0) * 0.5, weight);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
if (tapHorizonLimit < horizonLimit) {
|
||||||
|
tapHorizonLimit = computeWeightedHorizon(tapHorizonLimit, distanceSquared);
|
||||||
|
horizonLimit = min(horizonLimit, tapHorizonLimit);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
<@func declareBlurPass(axis)@>
|
#define HBAO_HORIZON_SEARCH_CONSTANT_STEP 0
|
||||||
|
|
||||||
<$declarePackOcclusionDepth()$>
|
float computeOcclusion(ivec4 side, vec2 fragUVPos, vec3 fragPositionES, TBNFrame fragFrameES, vec2 searchDir, float searchRadius, int stepCount) {
|
||||||
<$declareAmbientOcclusion()$>
|
float occlusion = 0.0;
|
||||||
|
#if HBAO_USE_COS_ANGLE
|
||||||
|
float horizonLimit = getFalloffCosAngle();
|
||||||
|
#else
|
||||||
|
float horizonLimit = getFalloffSinAngle();
|
||||||
|
#endif
|
||||||
|
|
||||||
// the source occlusion texture
|
if (stepCount>0) {
|
||||||
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap;
|
vec2 deltaTapUV = searchDir / float(stepCount);
|
||||||
|
vec2 tapUVPos;
|
||||||
|
float deltaRadius = searchRadius / float(stepCount);
|
||||||
|
vec2 sideDepthSize = getDepthTextureSideSize(0);
|
||||||
|
|
||||||
vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) {
|
#if HBAO_HORIZON_SEARCH_CONSTANT_STEP
|
||||||
raw = texelFetch(occlusionMap, coords, 0).xyz;
|
float radius = 0.0;
|
||||||
return unpackOcclusionDepth(raw);
|
int stepIndex;
|
||||||
}
|
|
||||||
|
|
||||||
vec2 fetchOcclusionDepth(ivec2 coords) {
|
for (stepIndex=0 ; stepIndex<stepCount ; stepIndex++) {
|
||||||
return unpackOcclusionDepth(texelFetch(occlusionMap, coords, 0).xyz);
|
fragUVPos += deltaTapUV;
|
||||||
}
|
radius += deltaRadius;
|
||||||
|
tapUVPos = snapToTexel(fragUVPos, sideDepthSize);
|
||||||
|
|
||||||
const int RADIUS_SCALE = 1;
|
<$computeHorizon()$>
|
||||||
const float BLUR_WEIGHT_OFFSET = 0.05;
|
}
|
||||||
const float BLUR_EDGE_SCALE = 2000.0;
|
#else
|
||||||
|
// Step is adapted to Mip level
|
||||||
|
float radius = deltaRadius;
|
||||||
|
float mipLevel = float(evalMipFromRadius(radius * float(doFetchMips())));
|
||||||
|
|
||||||
vec2 evalTapWeightedValue(ivec3 side, int r, ivec2 ssC, float key) {
|
while (radius<=searchRadius) {
|
||||||
ivec2 tapOffset = <$axis$> * (r * RADIUS_SCALE);
|
fragUVPos += deltaTapUV;
|
||||||
ivec2 ssP = (ssC + tapOffset);
|
tapUVPos = snapToTexel(fragUVPos, sideDepthSize);
|
||||||
|
|
||||||
if ((ssP.x < side.y || ssP.x >= side.z + side.y) || (ssP.y < 0 || ssP.y >= int(getWidthHeight(getResolutionLevel()).y))) {
|
<$computeHorizon()$>
|
||||||
return vec2(0.0);
|
|
||||||
}
|
|
||||||
vec2 tapOZ = fetchOcclusionDepth(ssC + tapOffset);
|
|
||||||
|
|
||||||
// spatial domain: offset gaussian tap
|
if (tapMipZ.x != mipLevel) {
|
||||||
float weight = BLUR_WEIGHT_OFFSET + getBlurCoef(abs(r));
|
mipLevel = tapMipZ.x;
|
||||||
|
deltaRadius *= 2.0;
|
||||||
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
deltaTapUV *= 2.0;
|
||||||
weight *= max(0.0, 1.0 - (getBlurEdgeSharpness() * BLUR_EDGE_SCALE) * abs(tapOZ.y - key));
|
sideDepthSize = getDepthTextureSideSize(int(mipLevel));
|
||||||
|
}
|
||||||
return vec2(tapOZ.x * weight, weight);
|
radius += deltaRadius;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
vec3 getBlurredOcclusion(vec2 coord) {
|
|
||||||
ivec2 ssC = ivec2(coord);
|
|
||||||
|
|
||||||
// Stereo side info
|
|
||||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
|
||||||
|
|
||||||
vec3 rawSample;
|
|
||||||
vec2 occlusionDepth = fetchOcclusionDepthRaw(ssC, rawSample);
|
|
||||||
float key = occlusionDepth.y;
|
|
||||||
|
|
||||||
// Central pixel contribution
|
|
||||||
float mainWeight = getBlurCoef(0);
|
|
||||||
vec2 weightedSums = vec2(occlusionDepth.x * mainWeight, mainWeight);
|
|
||||||
|
|
||||||
// Accumulate weighted contributions along the bluring axis in the [-radius, radius] range
|
|
||||||
int blurRadius = getBlurRadius();
|
|
||||||
// negative side first
|
|
||||||
for (int r = -blurRadius; r <= -1; ++r) {
|
|
||||||
weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key);
|
|
||||||
}
|
|
||||||
// then positive side
|
|
||||||
for (int r = 1; r <= blurRadius; ++r) {
|
|
||||||
weightedSums += evalTapWeightedValue(side.xyz, r, ssC, key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final normalization
|
#if HBAO_USE_COS_ANGLE
|
||||||
const float epsilon = 0.0001;
|
occlusion = min(occlusion * getFalloffCosAngleScale(), 1.0);
|
||||||
float result = weightedSums.x / (weightedSums.y + epsilon);
|
#else
|
||||||
|
occlusion = horizonLimit * mix(1.0, getFalloffSinAngleScale(), horizonLimit > 0.0);
|
||||||
rawSample.x = result;
|
#endif
|
||||||
return rawSample;
|
|
||||||
|
return occlusion;
|
||||||
|
}
|
||||||
|
|
||||||
|
float evalVisibilityHBAO(ivec4 side, vec2 fragUVPos, vec2 invSideImageSize, vec2 deltaTap, float diskPixelRadius,
|
||||||
|
vec3 fragPositionES, vec3 fragNormalES) {
|
||||||
|
vec2 pixelSearchVec = deltaTap * diskPixelRadius;
|
||||||
|
vec2 searchDir = pixelSearchVec * invSideImageSize;
|
||||||
|
vec2 deltaTapUV = deltaTap * invSideImageSize;
|
||||||
|
float obscuranceH1 = 0.0;
|
||||||
|
float obscuranceH2 = 0.0;
|
||||||
|
pixelSearchVec = abs(pixelSearchVec);
|
||||||
|
int stepCount = int(ceil(max(pixelSearchVec.x, pixelSearchVec.y)));
|
||||||
|
TBNFrame fragFrameES;
|
||||||
|
|
||||||
|
fragFrameES.tangent = vec3(0.0);
|
||||||
|
fragFrameES.binormal = vec3(0.0);
|
||||||
|
fragFrameES.normal = fragNormalES;
|
||||||
|
|
||||||
|
#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE
|
||||||
|
vec3 positionPos = buildPosition(side, fragUVPos + deltaTapUV);
|
||||||
|
vec3 positionNeg = buildPosition(side, fragUVPos - deltaTapUV);
|
||||||
|
|
||||||
|
fragFrameES.tangent = getMinDelta(fragPositionES, positionPos, positionNeg);
|
||||||
|
fragFrameES.tangent -= dot(fragNormalES, fragFrameES.tangent) * fragNormalES;
|
||||||
|
fragFrameES.tangent = normalize(fragFrameES.tangent);
|
||||||
|
#endif
|
||||||
|
// Forward search for h1
|
||||||
|
obscuranceH1 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, searchDir, diskPixelRadius, stepCount);
|
||||||
|
|
||||||
|
// Backward search for h2
|
||||||
|
#if HBAO_USE_OVERHANG_HACK || !HBAO_USE_COS_ANGLE
|
||||||
|
fragFrameES.tangent = -fragFrameES.tangent;
|
||||||
|
#endif
|
||||||
|
obscuranceH2 = computeOcclusion(side, fragUVPos, fragPositionES, fragFrameES, -searchDir, diskPixelRadius, stepCount);
|
||||||
|
|
||||||
|
return obscuranceH1 + obscuranceH2;
|
||||||
}
|
}
|
||||||
|
|
||||||
<@endfunc@>
|
<@endfunc@>
|
||||||
|
|
||||||
|
|
||||||
<@endif@>
|
<@endif@>
|
||||||
|
|
135
libraries/render-utils/src/ssao_bilateralBlur.slf
Normal file
135
libraries/render-utils/src/ssao_bilateralBlur.slf
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// ssao_bilateralBlur.frag
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 1/1/16.
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include ssao.slh@>
|
||||||
|
|
||||||
|
// Hack comment
|
||||||
|
|
||||||
|
<$declareAmbientOcclusion()$>
|
||||||
|
<$declareFetchDepthPyramidMap()$>
|
||||||
|
<$declarePackOcclusionDepth()$>
|
||||||
|
|
||||||
|
// the source occlusion texture
|
||||||
|
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap;
|
||||||
|
|
||||||
|
LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_BLUR_PARAMS) uniform blurParamsBuffer {
|
||||||
|
AmbientOcclusionBlurParams blurParams;
|
||||||
|
};
|
||||||
|
|
||||||
|
vec2 getBlurOcclusionAxis() {
|
||||||
|
return blurParams._blurAxis.xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 getBlurOcclusionUVLimit() {
|
||||||
|
return blurParams._blurAxis.zw;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 getBlurScales() {
|
||||||
|
return blurParams._blurInfo.xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getBlurRadius() {
|
||||||
|
return int(blurParams._blurInfo.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 fetchOcclusionPacked(ivec4 side, vec2 texCoord) {
|
||||||
|
texCoord.x = isStereo() ? (texCoord.x + float(getStereoSide(side)) * getBlurOcclusionUVLimit().x) * 0.5 : texCoord.x;
|
||||||
|
return textureLod(occlusionMap, texCoord, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float evalBlurCoefficient(vec3 blurScales, float radialDistance, float zDistance, float normalDistance) {
|
||||||
|
vec3 distances = vec3(radialDistance, zDistance, normalDistance);
|
||||||
|
return exp2(dot(blurScales, distances*distances));
|
||||||
|
}
|
||||||
|
|
||||||
|
const float BLUR_EDGE_NORMAL_LIMIT = 0.25;
|
||||||
|
|
||||||
|
vec2 evalTapWeightedValue(vec3 blurScales, ivec4 side, int r, vec2 occlusionTexCoord, float fragDepth, vec3 fragNormal) {
|
||||||
|
vec2 occlusionTexCoordLimits = getBlurOcclusionUVLimit();
|
||||||
|
|
||||||
|
if (any(lessThan(occlusionTexCoord, vec2(0.0))) || any(greaterThanEqual(occlusionTexCoord, occlusionTexCoordLimits)) ) {
|
||||||
|
return vec2(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 tapOcclusionPacked = fetchOcclusionPacked(side, occlusionTexCoord);
|
||||||
|
UnpackedOcclusion tap;
|
||||||
|
unpackOcclusionOutput(tapOcclusionPacked, tap);
|
||||||
|
|
||||||
|
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
||||||
|
float zDistance = tap.depth - fragDepth;
|
||||||
|
#if SSAO_BILATERAL_BLUR_USE_NORMAL
|
||||||
|
float normalDistance = BLUR_EDGE_NORMAL_LIMIT - min(BLUR_EDGE_NORMAL_LIMIT, dot(tap.normal, fragNormal));
|
||||||
|
#else
|
||||||
|
float normalDistance = 0.0;
|
||||||
|
#endif
|
||||||
|
float weight = evalBlurCoefficient(blurScales, float(abs(r)), zDistance, normalDistance);
|
||||||
|
|
||||||
|
return vec2(tap.occlusion * weight, weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 getBlurredOcclusion(ivec2 destPixelCoord, vec2 occlusionTexCoord, vec2 depthTexCoord) {
|
||||||
|
// Stereo side info
|
||||||
|
ivec4 side = getStereoSideInfo(destPixelCoord.x, 0);
|
||||||
|
|
||||||
|
float fragDepth = getZEyeAtUV(depthTexCoord, 0.0);
|
||||||
|
float fragDepthKey = CSZToDepthKey(fragDepth);
|
||||||
|
#if SSAO_BILATERAL_BLUR_USE_NORMAL
|
||||||
|
vec3 fragNormal = getNormalEyeAtUV(depthTexCoord, 0.0);
|
||||||
|
#else
|
||||||
|
vec3 fragNormal = vec3(0.0, 0.0, 1.0);
|
||||||
|
#endif
|
||||||
|
vec2 weightedSums = vec2(0.0);
|
||||||
|
|
||||||
|
// Accumulate weighted contributions along the bluring axis in the [-radius, radius] range
|
||||||
|
int blurRadius = getBlurRadius();
|
||||||
|
vec3 blurScales = getBlurScales();
|
||||||
|
int r;
|
||||||
|
|
||||||
|
// From now on, occlusionTexCoord is the UV pos in the side
|
||||||
|
float sideTexCoord = occlusionTexCoord.x * 2.0 - float(getStereoSide(side)) * getBlurOcclusionUVLimit().x;
|
||||||
|
occlusionTexCoord.x = mix(occlusionTexCoord.x, sideTexCoord, isStereo());
|
||||||
|
|
||||||
|
occlusionTexCoord -= getBlurOcclusionAxis() * float(blurRadius);
|
||||||
|
|
||||||
|
// negative side first
|
||||||
|
for (r = -blurRadius; r <= -1; r++) {
|
||||||
|
weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal);
|
||||||
|
occlusionTexCoord += getBlurOcclusionAxis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Central pixel contribution
|
||||||
|
float mainWeight = 1.0;
|
||||||
|
float pixelOcclusion = unpackOcclusion(fetchOcclusionPacked(side, occlusionTexCoord));
|
||||||
|
weightedSums += vec2(pixelOcclusion * mainWeight, mainWeight);
|
||||||
|
occlusionTexCoord += getBlurOcclusionAxis();
|
||||||
|
|
||||||
|
// then positive side
|
||||||
|
for (r = 1; r <= blurRadius; ++r) {
|
||||||
|
weightedSums += evalTapWeightedValue(blurScales, side, r, occlusionTexCoord, fragDepthKey, fragNormal);
|
||||||
|
occlusionTexCoord += getBlurOcclusionAxis();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final normalization
|
||||||
|
const float epsilon = 0.0001;
|
||||||
|
float result = weightedSums.x / (weightedSums.y + epsilon);
|
||||||
|
|
||||||
|
return packOcclusionOutput(result, fragDepth, fragNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(location=0) in vec4 varTexCoord0;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
outFragColor = getBlurredOcclusion(ivec2(gl_FragCoord.xy), varTexCoord0.xy, varTexCoord0.zw);
|
||||||
|
}
|
42
libraries/render-utils/src/ssao_bilateralBlur.slv
Normal file
42
libraries/render-utils/src/ssao_bilateralBlur.slv
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// ssao_bilateralBlur.vert
|
||||||
|
//
|
||||||
|
// Draw the unit quad [-1,-1 -> 1,1] filling in
|
||||||
|
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 9/12/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include gpu/Transform.slh@>
|
||||||
|
|
||||||
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
|
layout(location=0) out vec4 varTexCoord0;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||||
|
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||||
|
vec4(1.0, -1.0, 0.0, 1.0),
|
||||||
|
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||||
|
vec4(1.0, 1.0, 0.0, 1.0)
|
||||||
|
);
|
||||||
|
vec4 pos = UNIT_QUAD[gl_VertexID];
|
||||||
|
|
||||||
|
// standard transform but applied to the Texcoord
|
||||||
|
vec2 fullTexCoord = (pos.xy + 1.0) * 0.5;
|
||||||
|
vec4 tc = vec4(fullTexCoord, pos.zw);
|
||||||
|
|
||||||
|
TransformObject obj = getTransformObject();
|
||||||
|
<$transformModelToWorldPos(obj, tc, tc)$>
|
||||||
|
|
||||||
|
gl_Position = pos;
|
||||||
|
varTexCoord0.xy = tc.xy;
|
||||||
|
varTexCoord0.zw = fullTexCoord.xy;
|
||||||
|
}
|
42
libraries/render-utils/src/ssao_buildNormals.slf
Normal file
42
libraries/render-utils/src/ssao_buildNormals.slf
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// ssao_buildNormals.frag
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 09/19/18.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include ssao.slh@>
|
||||||
|
<$declareAmbientOcclusion()$>
|
||||||
|
<$declareFetchDepthPyramidMap()$>
|
||||||
|
|
||||||
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
// Pixel being shaded
|
||||||
|
vec2 fragCoord = gl_FragCoord.xy;
|
||||||
|
ivec2 fragPixelPos = ivec2(fragCoord.xy);
|
||||||
|
vec2 fragUVPos = varTexCoord0;
|
||||||
|
|
||||||
|
// Stereo side info based on the real viewport size of this pass
|
||||||
|
ivec2 sideNormalsSize = ivec2( getNormalsSideSize() );
|
||||||
|
ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideNormalsSize.x);
|
||||||
|
|
||||||
|
vec2 deltaDepthUV = vec2(1.0) / getDepthTextureSideSize(0);
|
||||||
|
|
||||||
|
// From now on, fragUVPos is the UV pos in the side
|
||||||
|
fragUVPos = getSideUVFromFramebufferUV(side, fragUVPos);
|
||||||
|
|
||||||
|
// The position and normal of the pixel fragment in Eye space
|
||||||
|
vec3 fragPositionES = buildPosition(side, fragUVPos);
|
||||||
|
vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV);
|
||||||
|
|
||||||
|
outFragColor = vec4(packNormal(fragNormalES), 1.0);
|
||||||
|
}
|
|
@ -37,96 +37,15 @@ vec2 getDebugCursorTexcoord(){
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 imageSize = getSideImageSize(getResolutionLevel());
|
// Stereo side info based on the real viewport size of this pass
|
||||||
|
vec2 sideDepthSize = getDepthTextureSideSize(0);
|
||||||
// In debug adjust the correct frag pixel based on base resolution
|
|
||||||
vec2 fragCoord = gl_FragCoord.xy;
|
|
||||||
if (getResolutionLevel() > 0) {
|
|
||||||
fragCoord /= float (1 << getResolutionLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pixel Debugged
|
// Pixel Debugged
|
||||||
vec2 cursorUV = getDebugCursorTexcoord();
|
vec2 cursorUV = getDebugCursorTexcoord();
|
||||||
vec2 cursorPixelPos = cursorUV * imageSize;
|
vec2 cursorPixelPos = cursorUV * sideDepthSize;
|
||||||
|
|
||||||
ivec2 ssC = ivec2(cursorPixelPos);
|
ivec2 fragUVPos = ivec2(cursorPixelPos);
|
||||||
|
|
||||||
// Fetch the z under the pixel (stereo or not)
|
|
||||||
float Zeye = getZEye(ssC, 0);
|
|
||||||
|
|
||||||
// Stereo side info
|
// TODO
|
||||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
|
||||||
|
|
||||||
// From now on, ssC is the pixel pos in the side
|
outFragColor = packOcclusionOutput(0.0, 0.0, vec3(0.0, 0.0, 1.0));
|
||||||
ssC.x -= side.y;
|
|
||||||
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize;
|
|
||||||
|
|
||||||
// The position and normal of the pixel fragment in Eye space
|
|
||||||
vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos);
|
|
||||||
vec3 Cn = evalEyeNormal(Cp);
|
|
||||||
|
|
||||||
// Choose the screen-space sample radius
|
|
||||||
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
|
|
||||||
|
|
||||||
vec2 fragToCursor = cursorPixelPos - fragCoord.xy;
|
|
||||||
if (dot(fragToCursor,fragToCursor) > ssDiskRadius * ssDiskRadius) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's make noise
|
|
||||||
//float randomPatternRotationAngle = getAngleDithering(ssC);
|
|
||||||
vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz;
|
|
||||||
float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp);
|
|
||||||
|
|
||||||
|
|
||||||
// Accumulate the Obscurance for each samples
|
|
||||||
float sum = 0.0;
|
|
||||||
float keepTapRadius = 1.0;
|
|
||||||
int keepedMip = -1;
|
|
||||||
bool keep = false;
|
|
||||||
int sampleCount = int(getNumSamples());
|
|
||||||
for (int i = 0; i < sampleCount; ++i) {
|
|
||||||
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize);
|
|
||||||
|
|
||||||
// The occluding point in camera space
|
|
||||||
vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy;
|
|
||||||
if (dot(fragToTap,fragToTap) < keepTapRadius) {
|
|
||||||
keep = true;
|
|
||||||
keepedMip = evalMipFromRadius(tap.z * float(doFetchMips()));
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
|
||||||
|
|
||||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
|
||||||
|
|
||||||
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
|
|
||||||
|
|
||||||
<! // KEEP IT for Debugging
|
|
||||||
// Bilateral box-filter over a quad for free, respecting depth edges
|
|
||||||
// (the difference that this makes is subtle)
|
|
||||||
if (abs(dFdx(Cp.z)) < 0.02) {
|
|
||||||
A -= dFdx(A) * ((ssC.x & 1) - 0.5);
|
|
||||||
}
|
|
||||||
if (abs(dFdy(Cp.z)) < 0.02) {
|
|
||||||
A -= dFdy(A) * ((ssC.y & 1) - 0.5);
|
|
||||||
}
|
|
||||||
!>
|
|
||||||
|
|
||||||
outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
|
|
||||||
|
|
||||||
if ((dot(fragToCursor,fragToCursor) < (100.0 * keepTapRadius * keepTapRadius) )) {
|
|
||||||
// outFragColor = vec4(vec3(A), 1.0);
|
|
||||||
outFragColor = vec4(vec3(A), 1.0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!keep) {
|
|
||||||
outFragColor = vec4(0.1);
|
|
||||||
} else {
|
|
||||||
outFragColor.rgb = colorWheel(float(keepedMip)/float(MAX_MIP_LEVEL));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
36
libraries/render-utils/src/ssao_gather.slf
Normal file
36
libraries/render-utils/src/ssao_gather.slf
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// ssao_gather.frag
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 09/19/2018.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
<@include ssao.slh@>
|
||||||
|
|
||||||
|
// Hack comment
|
||||||
|
|
||||||
|
<$declareAmbientOcclusion()$>
|
||||||
|
|
||||||
|
// the source occlusion texture
|
||||||
|
LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2DArray occlusionMaps;
|
||||||
|
|
||||||
|
layout(location=0) in vec4 varTexCoord0;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
// Gather the four splits of the occlusion result back into an interleaved full size
|
||||||
|
// result (at the resolution level, of course)
|
||||||
|
ivec2 destPixelCoord = ivec2(gl_FragCoord.xy);
|
||||||
|
ivec2 sourcePixelCoord = destPixelCoord >> SSAO_SPLIT_LOG2_COUNT;
|
||||||
|
ivec2 modPixelCoord = destPixelCoord & (SSAO_SPLIT_COUNT-1);
|
||||||
|
int occlusionMapIndex = modPixelCoord.x + (modPixelCoord.y << SSAO_SPLIT_LOG2_COUNT);
|
||||||
|
|
||||||
|
outFragColor = texelFetch(occlusionMaps, ivec3(sourcePixelCoord, occlusionMapIndex), 0);
|
||||||
|
}
|
|
@ -1,24 +0,0 @@
|
||||||
<@include gpu/Config.slh@>
|
|
||||||
<$VERSION_HEADER$>
|
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
|
||||||
//
|
|
||||||
// ssao_makeHorizontalBlur.frag
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 1/1/16.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
<@include ssao.slh@>
|
|
||||||
|
|
||||||
const ivec2 horizontal = ivec2(1,0);
|
|
||||||
<$declareBlurPass(horizontal)$>
|
|
||||||
|
|
||||||
|
|
||||||
layout(location=0) out vec4 outFragColor;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
outFragColor = vec4(getBlurredOcclusion(gl_FragCoord.xy), 1.0);
|
|
||||||
}
|
|
|
@ -19,71 +19,90 @@
|
||||||
|
|
||||||
<$declarePackOcclusionDepth()$>
|
<$declarePackOcclusionDepth()$>
|
||||||
|
|
||||||
|
#define SSAO_HBAO_MAX_RADIUS 300.0
|
||||||
|
|
||||||
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
|
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec2 imageSize = getSideImageSize(getResolutionLevel());
|
|
||||||
|
|
||||||
// Pixel being shaded
|
// Pixel being shaded
|
||||||
vec2 fragCoord = gl_FragCoord.xy;
|
vec2 fragCoord = gl_FragCoord.xy;
|
||||||
ivec2 ssC = ivec2(fragCoord.xy);
|
ivec2 fragPixelPos = ivec2(fragCoord.xy);
|
||||||
|
vec2 fragUVPos = varTexCoord0;
|
||||||
|
|
||||||
// Fetch the z under the pixel (stereo or not)
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
float Zeye = getZEye(ssC, 0);
|
vec3 fragNormalES = getNormalEyeAtUV(fragUVPos, 0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Stereo side info
|
// Stereo side info based on the real viewport size of this pass
|
||||||
ivec4 side = getStereoSideInfo(ssC.x, getResolutionLevel());
|
vec2 sideDepthSize = getDepthTextureSideSize(0);
|
||||||
|
ivec2 sideOcclusionSize;
|
||||||
// From now on, ssC is the pixel pos in the side
|
if (isHorizonBased()) {
|
||||||
ssC.x -= side.y;
|
sideOcclusionSize = ivec2( getOcclusionSplitSideSize() );
|
||||||
vec2 fragPos = (vec2(ssC) + vec2(0.5)) / imageSize;
|
} else {
|
||||||
|
sideOcclusionSize = ivec2( getOcclusionSideSize() );
|
||||||
// The position and normal of the pixel fragment in Eye space
|
|
||||||
vec3 Cp = evalEyePositionFromZeye(side.x, Zeye, fragPos);
|
|
||||||
vec3 Cn = evalEyeNormal(Cp);
|
|
||||||
|
|
||||||
// Choose the screen-space sample radius
|
|
||||||
float ssDiskRadius = evalDiskRadius(Cp.z, imageSize);
|
|
||||||
|
|
||||||
// Let's make noise
|
|
||||||
float randomPatternRotationAngle = getAngleDithering(ssC);
|
|
||||||
//vec3 wCp = (getViewInverse() * vec4(Cp, 1.0)).xyz;
|
|
||||||
//float randomPatternRotationAngle = getAngleDitheringWorldPos(wCp);
|
|
||||||
|
|
||||||
// Accumulate the Obscurance for each samples
|
|
||||||
float sum = 0.0;
|
|
||||||
int sampleCount = int(getNumSamples());
|
|
||||||
for (int i = 0; i < sampleCount; ++i) {
|
|
||||||
vec3 tap = getTapLocationClamped(i, randomPatternRotationAngle, ssDiskRadius, vec2(ssC), imageSize);
|
|
||||||
|
|
||||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
|
||||||
|
|
||||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
|
||||||
|
|
||||||
sum += float(tap.z > 0.0) * evalAO(Cp, Cn, Q);
|
|
||||||
}
|
}
|
||||||
|
ivec4 side = getStereoSideInfoFromWidth(fragPixelPos.x, sideOcclusionSize.x);
|
||||||
|
// From now on, fragUVPos is the UV pos in the side
|
||||||
|
fragUVPos = getSideUVFromFramebufferUV(side, fragUVPos);
|
||||||
|
fragUVPos = snapToTexel(fragUVPos, sideDepthSize);
|
||||||
|
|
||||||
float A = max(0.0, 1.0 - sum * getObscuranceScaling() * 5.0 * getInvNumSamples());
|
// The position and normal of the pixel fragment in Eye space
|
||||||
|
vec2 deltaDepthUV = vec2(2.0) / sideDepthSize;
|
||||||
|
vec3 fragPositionES = buildPosition(side, fragUVPos);
|
||||||
|
#if !SSAO_USE_QUAD_SPLIT
|
||||||
|
vec3 fragNormalES = buildNormal(side, fragUVPos, fragPositionES, deltaDepthUV);
|
||||||
|
#endif
|
||||||
|
|
||||||
// KEEP IT for Debugging
|
float occlusion = 1.0;
|
||||||
// Bilateral box-filter over a quad for free, respecting depth edges
|
|
||||||
// (the difference that this makes is subtle)
|
if (fragPositionES.z > (1.0-getPosLinearDepthFar())) {
|
||||||
if (abs(dFdx(Cp.z)) < 0.02) {
|
// Choose the screen-space sample radius
|
||||||
A -= dFdx(A) * (float(ssC.x & 1) - 0.5);
|
float diskPixelRadius = evalDiskRadius(fragPositionES.z, sideDepthSize);
|
||||||
|
if (isHorizonBased()) {
|
||||||
|
diskPixelRadius = min(diskPixelRadius, SSAO_HBAO_MAX_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's make noise
|
||||||
|
float randomPatternRotationAngle = 0.0;
|
||||||
|
|
||||||
|
// Accumulate the obscurance for each samples
|
||||||
|
float obscuranceSum = 0.0;
|
||||||
|
int numSamples = int(getNumSamples());
|
||||||
|
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 = 1.0 - obscuranceSum * getObscuranceScaling();
|
||||||
|
#else
|
||||||
|
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;
|
||||||
|
vec2 tapMipZ = fetchTap(side, tapUV, tap.z);
|
||||||
|
vec3 tapPositionES = evalEyePositionFromZeye(side.x, tapMipZ.y, tapUV);
|
||||||
|
obscuranceSum += float(tap.z > 0.0) * evalVisibilitySSAO(fragPositionES, fragNormalES, tapPositionES);
|
||||||
|
}
|
||||||
|
obscuranceSum *= invNumSamples;
|
||||||
|
obscuranceSum = 1.0 - obscuranceSum * getObscuranceScaling();
|
||||||
|
}
|
||||||
|
|
||||||
|
occlusion = clamp(obscuranceSum, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
if (abs(dFdy(Cp.z)) < 0.02) {
|
outFragColor = packOcclusionOutput(occlusion, fragPositionES.z, fragNormalES);
|
||||||
A -= dFdy(A) * (float(ssC.y & 1) - 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
outFragColor = vec4(packOcclusionDepth(A, CSZToDephtKey(Cp.z)), 1.0);
|
|
||||||
|
|
||||||
/* {
|
|
||||||
vec3 tap = getTapLocationClamped(2, randomPatternRotationAngle, ssDiskRadius, ssC, imageSize);
|
|
||||||
vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize);
|
|
||||||
vec2 fetchUV = vec2(tapUVZ.x + side.w * 0.5 * (side.x - tapUVZ.x), tapUVZ.y);
|
|
||||||
vec3 Q = evalEyePositionFromZeye(side.x, tapUVZ.z, tapUVZ.xy);
|
|
||||||
outFragColor = vec4(fetchUV, 0.0, 1.0);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<@include gpu/Config.slh@>
|
|
||||||
<$VERSION_HEADER$>
|
|
||||||
// Generated on <$_SCRIBE_DATE$>
|
|
||||||
//
|
|
||||||
// ssao_makeVerticalBlur.frag
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 1/1/16.
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
<@include ssao.slh@>
|
|
||||||
|
|
||||||
const ivec2 vertical = ivec2(0,1);
|
|
||||||
<$declareBlurPass(vertical)$>
|
|
||||||
|
|
||||||
layout(location=0) out vec4 outFragColor;
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
float occlusion = getBlurredOcclusion(gl_FragCoord.xy).x;
|
|
||||||
outFragColor = vec4(occlusion, 0.0, 0.0, occlusion);
|
|
||||||
}
|
|
28
libraries/render-utils/src/ssao_mip_depth.slf
Normal file
28
libraries/render-utils/src/ssao_mip_depth.slf
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<@include gpu/Config.slh@>
|
||||||
|
<$VERSION_HEADER$>
|
||||||
|
// Generated on <$_SCRIBE_DATE$>
|
||||||
|
//
|
||||||
|
// ssao_mip_depth.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 4/18/18.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
<@include gpu/ShaderConstants.h@>
|
||||||
|
|
||||||
|
LAYOUT(binding=GPU_TEXTURE_MIP_CREATION_INPUT) uniform sampler2D depthTexture;
|
||||||
|
|
||||||
|
layout(location=0) in vec2 varTexCoord0;
|
||||||
|
|
||||||
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
vec4 depths = textureGather(depthTexture, varTexCoord0);
|
||||||
|
// Keep the minimum depth
|
||||||
|
float outZ = min(depths.w, min(depths.z, min(depths.x, depths.y)));
|
||||||
|
|
||||||
|
outFragColor = vec4(vec3(outZ), 1.0);
|
||||||
|
}
|
64
libraries/render-utils/src/ssao_shared.h
Normal file
64
libraries/render-utils/src/ssao_shared.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// <!
|
||||||
|
// Created by Olivier Prat on 2018/09/18
|
||||||
|
// Copyright 2013-2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
// !>
|
||||||
|
|
||||||
|
// <@if not RENDER_UTILS_SSAO_SHARED_H@>
|
||||||
|
// <@def RENDER_UTILS_SSAO_SHARED_H@>
|
||||||
|
|
||||||
|
// Hack comment to absorb the extra '//' scribe prepends
|
||||||
|
|
||||||
|
#ifndef RENDER_UTILS_SSAO_SHARED_H
|
||||||
|
#define RENDER_UTILS_SSAO_SHARED_H
|
||||||
|
|
||||||
|
#define SSAO_USE_QUAD_SPLIT 1
|
||||||
|
#define SSAO_BILATERAL_BLUR_USE_NORMAL 0
|
||||||
|
|
||||||
|
#define SSAO_DEPTH_KEY_SCALE 300.0
|
||||||
|
|
||||||
|
#if SSAO_USE_QUAD_SPLIT
|
||||||
|
#define SSAO_SPLIT_LOG2_COUNT 2
|
||||||
|
#else
|
||||||
|
#define SSAO_SPLIT_LOG2_COUNT 0
|
||||||
|
#endif
|
||||||
|
#define SSAO_SPLIT_COUNT (1 << SSAO_SPLIT_LOG2_COUNT)
|
||||||
|
|
||||||
|
// glsl / C++ compatible source as interface for ambient occlusion
|
||||||
|
#ifdef __cplusplus
|
||||||
|
# define SSAO_VEC4 glm::vec4
|
||||||
|
# define SSAO_MAT4 glm::mat4
|
||||||
|
#else
|
||||||
|
# define SSAO_VEC4 vec4
|
||||||
|
# define SSAO_MAT4 mat4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct AmbientOcclusionParams {
|
||||||
|
SSAO_VEC4 _resolutionInfo;
|
||||||
|
SSAO_VEC4 _radiusInfo;
|
||||||
|
SSAO_VEC4 _ditheringInfo;
|
||||||
|
SSAO_VEC4 _sampleInfo;
|
||||||
|
SSAO_VEC4 _falloffInfo;
|
||||||
|
SSAO_VEC4 _sideSizes[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AmbientOcclusionFrameParams {
|
||||||
|
SSAO_VEC4 _angleInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AmbientOcclusionBlurParams {
|
||||||
|
SSAO_VEC4 _blurInfo;
|
||||||
|
SSAO_VEC4 _blurAxis;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENDER_UTILS_SHADER_CONSTANTS_H
|
||||||
|
|
||||||
|
// <@if 1@>
|
||||||
|
// Trigger Scribe include
|
||||||
|
// <@endif@> <!def that !>
|
||||||
|
|
||||||
|
// <@endif@>
|
||||||
|
|
||||||
|
// Hack Comment
|
|
@ -26,9 +26,7 @@ layout(location=1) out vec4 outNormal;
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// Gather 2 by 2 quads from texture and downsample
|
// Gather 2 by 2 quads from texture and downsample
|
||||||
|
|
||||||
// Try different filters for Z
|
|
||||||
vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
|
vec4 Zeyes = textureGather(linearDepthMap, varTexCoord0, 0);
|
||||||
// float Zeye = texture(linearDepthMap, varTexCoord0).x;
|
|
||||||
|
|
||||||
vec4 rawNormalsX = textureGather(normalMap, varTexCoord0, 0);
|
vec4 rawNormalsX = textureGather(normalMap, varTexCoord0, 0);
|
||||||
vec4 rawNormalsY = textureGather(normalMap, varTexCoord0, 1);
|
vec4 rawNormalsY = textureGather(normalMap, varTexCoord0, 1);
|
||||||
|
|
|
@ -25,7 +25,7 @@ LAYOUT(binding=0) uniform blurParamsBuffer {
|
||||||
BlurParameters parameters;
|
BlurParameters parameters;
|
||||||
};
|
};
|
||||||
|
|
||||||
vec2 getViewportInvWidthHeight() {
|
vec2 getInvWidthHeight() {
|
||||||
return parameters.resolutionInfo.zw;
|
return parameters.resolutionInfo.zw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0;
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(1.0, 0.0), getViewportInvWidthHeight());
|
outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(1.0, 0.0), getInvWidthHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0;
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(0.0, 1.0), getViewportInvWidthHeight());
|
outFragColor = pixelShaderGaussianDepthAware(varTexCoord0, vec2(0.0, 1.0), getInvWidthHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,6 @@ layout(location=0) in vec2 varTexCoord0;
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = pixelShaderGaussian(varTexCoord0, vec2(1.0, 0.0), getViewportInvWidthHeight());
|
outFragColor = pixelShaderGaussian(varTexCoord0, vec2(1.0, 0.0), getInvWidthHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,6 @@ layout(location=0) in vec2 varTexCoord0;
|
||||||
layout(location=0) out vec4 outFragColor;
|
layout(location=0) out vec4 outFragColor;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = pixelShaderGaussian(varTexCoord0, vec2(0.0, 1.0), getViewportInvWidthHeight());
|
outFragColor = pixelShaderGaussian(varTexCoord0, vec2(0.0, 1.0), getInvWidthHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,3 +13,4 @@ precision highp float;
|
||||||
precision highp samplerBuffer;
|
precision highp samplerBuffer;
|
||||||
precision highp sampler2DShadow;
|
precision highp sampler2DShadow;
|
||||||
precision highp sampler2DArrayShadow;
|
precision highp sampler2DArrayShadow;
|
||||||
|
precision lowp sampler2DArray;
|
||||||
|
|
21
libraries/shared/src/MathUtils.h
Normal file
21
libraries/shared/src/MathUtils.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// MathUtils.h
|
||||||
|
// libraries/shared/src
|
||||||
|
//
|
||||||
|
// Created by Olivier Prat on 9/21/18.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_MathUtils_h
|
||||||
|
#define hifi_MathUtils_h
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T divideRoundUp(const T& numerator, int divisor) {
|
||||||
|
return (numerator + divisor - T(1)) / divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_MathUtils_h
|
||||||
|
|
|
@ -7,48 +7,60 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
import QtQuick 2.5
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import "qrc:///qml/styles-uit"
|
||||||
|
import "qrc:///qml/controls-uit" as HifiControls
|
||||||
|
|
||||||
import "configSlider"
|
import "configSlider"
|
||||||
import "../lib/plotperf"
|
import "../lib/plotperf"
|
||||||
|
|
||||||
Column {
|
Rectangle {
|
||||||
spacing: 8
|
HifiConstants { id: hifi;}
|
||||||
|
id: root;
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
|
color: hifi.colors.baseGray;
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: surfaceGeometry
|
id: surfaceGeometry
|
||||||
spacing: 10
|
spacing: 8
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.margins: hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
Column{
|
Repeater {
|
||||||
Repeater {
|
model: [
|
||||||
model: [
|
"Blur Edge Sharpness:edgeSharpness:1.0:false",
|
||||||
"Radius:radius:2.0:false",
|
"Blur Radius:blurRadius:15.0:true",
|
||||||
"Level:obscuranceLevel:1.0:false",
|
"Resolution Downscale:resolutionLevel:2:true",
|
||||||
"Num Taps:numSamples:32:true",
|
]
|
||||||
"Taps Spiral:numSpiralTurns:10.0:false",
|
ConfigSlider {
|
||||||
"Falloff Bias:falloffBias:0.2:false",
|
label: qsTr(modelData.split(":")[0])
|
||||||
"Edge Sharpness:edgeSharpness:1.0:false",
|
integral: (modelData.split(":")[3] == 'true')
|
||||||
"Blur Radius:blurRadius:10.0:false",
|
config: Render.getConfig("RenderMainView.AmbientOcclusion")
|
||||||
]
|
property: modelData.split(":")[1]
|
||||||
ConfigSlider {
|
max: modelData.split(":")[2]
|
||||||
label: qsTr(modelData.split(":")[0])
|
min: 0.0
|
||||||
integral: (modelData.split(":")[3] == 'true')
|
height:38
|
||||||
config: Render.getConfig("RenderMainView.AmbientOcclusion")
|
|
||||||
property: modelData.split(":")[1]
|
|
||||||
max: modelData.split(":")[2]
|
|
||||||
min: 0.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row{
|
|
||||||
|
Row {
|
||||||
|
spacing: 10
|
||||||
Column {
|
Column {
|
||||||
Repeater {
|
Repeater {
|
||||||
model: [
|
model: [
|
||||||
"resolutionLevel:resolutionLevel",
|
"horizonBased:horizonBased",
|
||||||
|
"jitterEnabled:jitterEnabled",
|
||||||
"ditheringEnabled:ditheringEnabled",
|
"ditheringEnabled:ditheringEnabled",
|
||||||
"fetchMipsEnabled:fetchMipsEnabled",
|
"fetchMipsEnabled:fetchMipsEnabled",
|
||||||
"borderingEnabled:borderingEnabled"
|
"borderingEnabled:borderingEnabled"
|
||||||
]
|
]
|
||||||
CheckBox {
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
text: qsTr(modelData.split(":")[0])
|
text: qsTr(modelData.split(":")[0])
|
||||||
checked: Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]]
|
checked: Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]]
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]] = checked }
|
onCheckedChanged: { Render.getConfig("RenderMainView.AmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||||
|
@ -60,7 +72,8 @@ Column {
|
||||||
model: [
|
model: [
|
||||||
"debugEnabled:showCursorPixel"
|
"debugEnabled:showCursorPixel"
|
||||||
]
|
]
|
||||||
CheckBox {
|
HifiControls.CheckBox {
|
||||||
|
boxSize: 20
|
||||||
text: qsTr(modelData.split(":")[0])
|
text: qsTr(modelData.split(":")[0])
|
||||||
checked: Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]]
|
checked: Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]]
|
||||||
onCheckedChanged: { Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]] = checked }
|
onCheckedChanged: { Render.getConfig("RenderMainView.DebugAmbientOcclusion")[modelData.split(":")[1]] = checked }
|
||||||
|
@ -84,5 +97,81 @@ Column {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,53 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
//
|
//
|
||||||
// debugSurfaceGeometryPass.js
|
// debugAmbientOcclusionPass.js
|
||||||
|
// tablet-sample-app
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 6/6/2016
|
// Created by Olivier Prat on April 19 2018.
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
// Set up the qml ui
|
(function() {
|
||||||
var qml = Script.resolvePath('ambientOcclusionPass.qml');
|
var AppUi = Script.require('appUi');
|
||||||
var window = new OverlayWindow({
|
|
||||||
title: 'Ambient Occlusion Pass',
|
|
||||||
source: qml,
|
|
||||||
width: 400, height: 300,
|
|
||||||
});
|
|
||||||
window.setPosition(Window.innerWidth - 420, 50 + 550 + 50);
|
|
||||||
window.closed.connect(function() { Script.stop(); });
|
|
||||||
|
|
||||||
|
var onMousePressEvent = function (e) {
|
||||||
|
};
|
||||||
|
Controller.mousePressEvent.connect(onMousePressEvent);
|
||||||
|
|
||||||
var moveDebugCursor = false;
|
var onMouseReleaseEvent = function () {
|
||||||
Controller.mousePressEvent.connect(function (e) {
|
};
|
||||||
if (e.isMiddleButton) {
|
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
|
||||||
moveDebugCursor = true;
|
|
||||||
setDebugCursor(e.x, e.y);
|
var onMouseMoveEvent = function (e) {
|
||||||
|
};
|
||||||
|
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
|
||||||
|
|
||||||
|
function fromQml(message) {
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
Controller.mouseReleaseEvent.connect(function() { moveDebugCursor = false; });
|
|
||||||
Controller.mouseMoveEvent.connect(function (e) { if (moveDebugCursor) setDebugCursor(e.x, e.y); });
|
|
||||||
|
|
||||||
|
var ui;
|
||||||
function setDebugCursor(x, y) {
|
function startup() {
|
||||||
nx = (x / Window.innerWidth);
|
ui = new AppUi({
|
||||||
ny = 1.0 - ((y) / (Window.innerHeight - 32));
|
buttonName: "AO",
|
||||||
|
home: Script.resolvePath("ambientOcclusionPass.qml"),
|
||||||
Render.getConfig("RenderMainView").getConfig("DebugAmbientOcclusion").debugCursorTexcoord = { x: nx, y: ny };
|
onMessage: fromQml,
|
||||||
}
|
//normalButton: Script.resolvePath("../../../system/assets/images/ao-i.svg"),
|
||||||
|
//activeButton: Script.resolvePath("../../../system/assets/images/ao-a.svg")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
startup();
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
Controller.mousePressEvent.disconnect(onMousePressEvent);
|
||||||
|
Controller.mouseReleaseEvent.disconnect(onMouseReleaseEvent);
|
||||||
|
Controller.mouseMoveEvent.disconnect(onMouseMoveEvent);
|
||||||
|
pages.clear();
|
||||||
|
// killEngineInspectorView();
|
||||||
|
// killCullInspectorView();
|
||||||
|
// killEngineLODWindow();
|
||||||
|
});
|
||||||
|
}());
|
||||||
|
|
|
@ -204,6 +204,7 @@ Rectangle {
|
||||||
ListElement { text: "Debug Scattering"; color: "White" }
|
ListElement { text: "Debug Scattering"; color: "White" }
|
||||||
ListElement { text: "Ambient Occlusion"; color: "White" }
|
ListElement { text: "Ambient Occlusion"; color: "White" }
|
||||||
ListElement { text: "Ambient Occlusion Blurred"; color: "White" }
|
ListElement { text: "Ambient Occlusion Blurred"; color: "White" }
|
||||||
|
ListElement { text: "Ambient Occlusion Normal"; color: "White" }
|
||||||
ListElement { text: "Velocity"; color: "White" }
|
ListElement { text: "Velocity"; color: "White" }
|
||||||
ListElement { text: "Custom"; color: "White" }
|
ListElement { text: "Custom"; color: "White" }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue