mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 16:33:56 +02:00
Introducing the sl files and the blurring stages
This commit is contained in:
parent
8dba66fb14
commit
52f3c7e2cb
24 changed files with 579 additions and 787 deletions
|
@ -12,7 +12,7 @@
|
|||
Script.include("cookies.js");
|
||||
|
||||
var MENU = "Developer>Render>Debug Deferred Buffer";
|
||||
var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "AmbientOcclusion", "Custom"];
|
||||
var ACTIONS = ["Off", "Diffuse", "AmbientOcclusion", "Specular", "Roughness", "Normal", "Depth", "Lighting", "PyramidDepth", "OcclusionRaw", "OcclusionBlurred", "Custom"];
|
||||
var SETTINGS_KEY = "EngineDebugScript.DebugMode";
|
||||
|
||||
Number.prototype.clamp = function(min, max) {
|
||||
|
@ -52,6 +52,7 @@ var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D);
|
|||
|
||||
var resizing = false;
|
||||
var previousMode = Settings.getValue(SETTINGS_KEY, -1);
|
||||
previousMode = 1;
|
||||
Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]);
|
||||
Render.deferredDebugMode = previousMode;
|
||||
Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size
|
||||
|
@ -98,6 +99,11 @@ panel.newSlider("Tone Mapping Exposure", -10, 10,
|
|||
function() { return Render.tone.exposure; },
|
||||
function (value) { return (value); });
|
||||
|
||||
panel.newSlider("Ambient Occlusion Radius", 0.0, 2.0,
|
||||
function (value) { Render.ambientOcclusion.radius = value; },
|
||||
function() { return Render.ambientOcclusion.radius; },
|
||||
function (value) { return (value); });
|
||||
|
||||
var tickTackPeriod = 500;
|
||||
|
||||
function updateCounters() {
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
#include <algorithm> //min max and more
|
||||
|
||||
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <gpu/Context.h>
|
||||
|
@ -24,19 +27,16 @@
|
|||
#include "ViewFrustum.h"
|
||||
#include "GeometryCache.h"
|
||||
|
||||
#include "ambient_occlusion_vert.h"
|
||||
#include "ambient_occlusion_frag.h"
|
||||
#include "gaussian_blur_vertical_vert.h"
|
||||
#include "gaussian_blur_horizontal_vert.h"
|
||||
#include "gaussian_blur_frag.h"
|
||||
#include "occlusion_blend_frag.h"
|
||||
|
||||
|
||||
#include "ssao_makePyramid_frag.h"
|
||||
#include "ssao_makeOcclusion_frag.h"
|
||||
#include "ssao_makeHorizontalBlur_frag.h"
|
||||
#include "ssao_makeVerticalBlur_frag.h"
|
||||
|
||||
const int AmbientOcclusionEffect_ParamsSlot = 0;
|
||||
const int AmbientOcclusionEffect_DeferredTransformSlot = 1;
|
||||
const int AmbientOcclusionEffect_DepthMapSlot = 0;
|
||||
const int AmbientOcclusionEffect_PyramidMapSlot = 0;
|
||||
const int AmbientOcclusionEffect_OcclusionMapSlot = 0;
|
||||
|
||||
AmbientOcclusionEffect::AmbientOcclusionEffect() {
|
||||
Parameters parameters;
|
||||
|
@ -45,44 +45,8 @@ AmbientOcclusionEffect::AmbientOcclusionEffect() {
|
|||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() {
|
||||
if (!_pyramidPipeline) {
|
||||
const char AO_frag[] = R"SCRIBE(#version 410 core
|
||||
//
|
||||
// Created by Sam Gateau on 12/23/2015
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
struct AmbientOcclusionParams {
|
||||
vec4 _clipInfo;
|
||||
mat4 _projection;
|
||||
vec4 _radius_s0_s1_s2;
|
||||
};
|
||||
|
||||
uniform ambientOcclusionParamsBuffer {
|
||||
AmbientOcclusionParams params;
|
||||
};
|
||||
|
||||
float evalZeyeFromZdb(float depth) {
|
||||
return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z);
|
||||
}
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
float Zdb = texture(depthMap, varTexCoord0).x;
|
||||
float Zeye = -evalZeyeFromZdb(Zdb);
|
||||
outFragColor = vec4(Zeye, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(AO_frag));
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_makePyramid_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
|
@ -108,210 +72,8 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getPyramidPipeline() {
|
|||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() {
|
||||
if (!_occlusionPipeline) {
|
||||
const char AO_frag[] = R"SCRIBE(#version 410 core
|
||||
//
|
||||
// Created by Sam Gateau on 12/23/2015
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
const int NUM_SAMPLES = 11;
|
||||
const int NUM_SPIRAL_TURNS= 7;
|
||||
const int LOG_MAX_OFFSET = 3;
|
||||
const int MAX_MIP_LEVEL = 5;
|
||||
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D pyramidMap;
|
||||
|
||||
float getZeye(vec2 texcoord) {
|
||||
return -texture(pyramidMap, texcoord, 0).x;
|
||||
}
|
||||
|
||||
struct AmbientOcclusionParams {
|
||||
vec4 _clipInfo;
|
||||
mat4 _projection;
|
||||
vec4 _radius_s0_s1_s2;
|
||||
};
|
||||
|
||||
uniform ambientOcclusionParamsBuffer {
|
||||
AmbientOcclusionParams params;
|
||||
};
|
||||
|
||||
float getProjScale() {
|
||||
return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0
|
||||
}
|
||||
|
||||
float getRadius() {
|
||||
return params._radius_s0_s1_s2.x;
|
||||
}
|
||||
|
||||
vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) {
|
||||
// compute the view space position using the depth
|
||||
// basically manually pick the proj matrix components to do the inverse
|
||||
float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0];
|
||||
float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1];
|
||||
return vec3(Xe, Ye, Zeye);
|
||||
}
|
||||
|
||||
vec3 evalEyePosition(vec2 texcoord) {
|
||||
float Zeye = getZeye(texcoord);
|
||||
return evalEyePositionFromZeye(Zeye, texcoord);
|
||||
}
|
||||
|
||||
vec3 evalEyeNormal(vec3 C) {
|
||||
return -normalize(cross(dFdy(C), dFdx(C)));
|
||||
}
|
||||
|
||||
|
||||
/** Used for packing Z into the GB channels */
|
||||
float CSZToKey(float z) {
|
||||
return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0);
|
||||
}
|
||||
|
||||
|
||||
/** Used for packing Z into the GB channels */
|
||||
void packKey(float key, out vec2 p) {
|
||||
|
||||
// Round to the nearest 1/256.0
|
||||
float temp = floor(key * 256.0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Integer part
|
||||
p.x = temp * (1.0 / 256.0);
|
||||
|
||||
// Fractional part
|
||||
p.y = key * 256.0 - temp;
|
||||
}
|
||||
|
||||
|
||||
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
|
||||
// Radius relative to ssR
|
||||
float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES);
|
||||
float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
|
||||
|
||||
ssR = alpha;
|
||||
return vec2(cos(angle), sin(angle));
|
||||
}
|
||||
in vec2 varTexCoord0;
|
||||
|
||||
vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
|
||||
// Derivation:
|
||||
// mipLevel = floor(log(ssR / MAX_OFFSET));
|
||||
int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
|
||||
|
||||
ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
|
||||
|
||||
vec3 P;
|
||||
|
||||
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
|
||||
// Manually clamp to the texture size because texelFetch bypasses the texture unit
|
||||
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1));
|
||||
P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
|
||||
|
||||
// Offset to pixel center
|
||||
//P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
|
||||
|
||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0);
|
||||
P = evalEyePositionFromZeye(P.z, tapUV);
|
||||
return P;
|
||||
}
|
||||
|
||||
|
||||
float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) {
|
||||
// Offset on the unit disk, spun for this pixel
|
||||
float ssR;
|
||||
vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
|
||||
ssR *= ssDiskRadius;
|
||||
|
||||
// The occluding point in camera space
|
||||
vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
|
||||
|
||||
vec3 v = Q - C;
|
||||
|
||||
float vv = dot(v, v);
|
||||
float vn = dot(v, n_C);
|
||||
|
||||
const float bias = 0.01;
|
||||
const float epsilon = 0.01;
|
||||
const float radius2 = 0.5 * 0.5;
|
||||
|
||||
// A: From the HPG12 paper
|
||||
// Note large epsilon to avoid overdarkening within cracks
|
||||
// return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
|
||||
|
||||
// B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
|
||||
float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
|
||||
|
||||
// C: Medium contrast (which looks better at high radii), no division. Note that the
|
||||
// contribution still falls off with radius^2, but we've adjusted the rate in a way that is
|
||||
// more computationally efficient and happens to be aesthetically pleasing.
|
||||
// return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
|
||||
|
||||
// D: Low contrast, no division operation
|
||||
// return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
|
||||
}
|
||||
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
vec3 debugValue(float f, float scale) {
|
||||
if (f < 0.0) {
|
||||
return vec3((scale + f) / scale, 0.0, 0.0);
|
||||
} else {
|
||||
return vec3(0.0, (scale - f) / scale, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// Pixel being shaded
|
||||
ivec2 ssC = ivec2(gl_FragCoord.xy);
|
||||
|
||||
vec3 Cp = evalEyePosition(varTexCoord0);
|
||||
|
||||
// packKey(CSZToKey(Cp.z), bilateralKey);
|
||||
|
||||
// Hash function used in the HPG12 AlchemyAO paper
|
||||
float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10;
|
||||
|
||||
|
||||
vec3 Cn = evalEyeNormal(Cp);
|
||||
|
||||
// Choose the screen-space sample radius
|
||||
// proportional to the projected area of the sphere
|
||||
float ssDiskRadius = -getProjScale() * getRadius() / Cp.z;
|
||||
|
||||
float sum = 0.0;
|
||||
for (int i = 0; i < NUM_SAMPLES; ++i) {
|
||||
sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
|
||||
}
|
||||
|
||||
float intensityDivR6 = 1.0;
|
||||
float A = max(0.0, 1.0 - sum * intensityDivR6 * (5.0 / NUM_SAMPLES));
|
||||
|
||||
// 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(debugValue(Cn.y, 10), A);
|
||||
outFragColor = vec4(debugValue(Cn.y, 1), A);
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(AO_frag));
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_makeOcclusion_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
|
@ -327,8 +89,7 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() {
|
|||
// Stencil test all the ao passes for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
// state->setColorWriteMask(false, false, false, true);
|
||||
state->setColorWriteMask(true, true, true, true);
|
||||
state->setColorWriteMask(true, true, true, false);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_occlusionPipeline = gpu::Pipeline::create(program, state);
|
||||
|
@ -336,77 +97,148 @@ const gpu::PipelinePointer& AmbientOcclusionEffect::getOcclusionPipeline() {
|
|||
return _occlusionPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() {
|
||||
if (!_vBlurPipeline) {
|
||||
auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);
|
||||
|
||||
// Link the horizontal blur FBO to texture
|
||||
/* _vBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
|
||||
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
|
||||
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
auto width = _vBlurBuffer->getWidth();
|
||||
auto height = _vBlurBuffer->getHeight();
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
|
||||
*/
|
||||
// Good to go add the brand new pipeline
|
||||
_vBlurPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _vBlurPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getHBlurPipeline() {
|
||||
if (!_hBlurPipeline) {
|
||||
auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert));
|
||||
auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag));
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_makeHorizontalBlur_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
state->setDepthTest(false, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO);
|
||||
|
||||
/* // Link the horizontal blur FBO to texture
|
||||
_hBlurBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create(gpu::Element::COLOR_RGBA_32,
|
||||
DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width(), DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height()));
|
||||
auto format = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
auto width = _hBlurBuffer->getWidth();
|
||||
auto height = _hBlurBuffer->getHeight();
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler));
|
||||
*/
|
||||
|
||||
// Stencil test all the ao passes for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
state->setColorWriteMask(true, true, true, false);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_hBlurPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _hBlurPipeline;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& AmbientOcclusionEffect::getVBlurPipeline() {
|
||||
if (!_vBlurPipeline) {
|
||||
auto vs = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(ssao_makeVerticalBlur_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("ambientOcclusionParamsBuffer"), AmbientOcclusionEffect_ParamsSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredTransformBuffer"), AmbientOcclusionEffect_DeferredTransformSlot));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("occlusionMap"), AmbientOcclusionEffect_OcclusionMapSlot));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
||||
// Stencil test all the ao passes for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
// Vertical blur write just the final result Occlusion value in the alpha channel
|
||||
state->setColorWriteMask(false, false, false, true);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_vBlurPipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
const char blur_frag[] = R"SCRIBE(#version 410 core
|
||||
//
|
||||
// Created by Sam Gateau on 12/31/2015
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
struct AmbientOcclusionParams {
|
||||
vec4 _clipInfo;
|
||||
mat4 _projection;
|
||||
vec4 _radius_s0_s1_s2;
|
||||
};
|
||||
|
||||
uniform ambientOcclusionParamsBuffer {
|
||||
AmbientOcclusionParams params;
|
||||
};
|
||||
|
||||
float evalZeyeFromZdb(float depth) {
|
||||
return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z);
|
||||
}
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
ivec2 ssC = ivec2(gl_FragCoord.xy);
|
||||
|
||||
vec4 temp = texelFetch(source, ssC, 0);
|
||||
|
||||
keyPassThrough = temp.KEY_COMPONENTS;
|
||||
float key = unpackKey(keyPassThrough);
|
||||
|
||||
VALUE_TYPE sum = temp.VALUE_COMPONENTS;
|
||||
|
||||
if (key == 1.0) {
|
||||
// Sky pixel (if you aren't using depth keying, disable this test)
|
||||
result = sum;
|
||||
return;
|
||||
}
|
||||
|
||||
// Base weight for depth falloff. Increase this for more blurriness,
|
||||
// decrease it for better edge discrimination
|
||||
float BASE = gaussian[0];
|
||||
float totalWeight = BASE;
|
||||
sum *= totalWeight;
|
||||
|
||||
|
||||
for (int r = -R; r <= R; ++r) {
|
||||
// We already handled the zero case above. This loop should be unrolled and the static branch optimized out,
|
||||
// so the IF statement has no runtime cost
|
||||
if (r != 0) {
|
||||
temp = texelFetch(source, ssC + axis * (r * SCALE), 0);
|
||||
float tapKey = unpackKey(temp.KEY_COMPONENTS);
|
||||
VALUE_TYPE value = temp.VALUE_COMPONENTS;
|
||||
|
||||
// spatial domain: offset gaussian tap
|
||||
float weight = 0.3 + gaussian[abs(r)];
|
||||
|
||||
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
|
||||
weight *= max(0.0, 1.0
|
||||
- (EDGE_SHARPNESS * 2000.0) * abs(tapKey - key)
|
||||
);
|
||||
|
||||
sum += value * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
}
|
||||
|
||||
const float epsilon = 0.0001;
|
||||
result = sum / (totalWeight + epsilon);
|
||||
|
||||
)SCRIBE";
|
||||
}
|
||||
return _vBlurPipeline;
|
||||
}
|
||||
|
||||
|
||||
void AmbientOcclusionEffect::setClipInfo(float nearZ, float farZ) {
|
||||
_parametersBuffer.edit<Parameters>()._clipInfo = glm::vec4(nearZ*farZ, farZ -nearZ, -farZ, 0.0f);
|
||||
|
||||
}
|
||||
|
||||
void AmbientOcclusionEffect::setRadius(float radius) {
|
||||
radius = std::max(0.01f, radius);
|
||||
_parametersBuffer.edit<Parameters>()._radius_radius2_InvRadius6_s2 = glm::vec4(radius, radius * radius, 1.0f / pow(radius, 6.0f), 0.0f);
|
||||
}
|
||||
|
||||
void AmbientOcclusionEffect::updateDeferredTransformBuffer(const render::RenderContextPointer& renderContext) {
|
||||
// Allocate the parameters buffer used by all the deferred shaders
|
||||
if (!_deferredTransformBuffer[0]._buffer) {
|
||||
|
@ -515,7 +347,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
auto depthBuffer = framebufferCache->getPrimaryDepthTexture();
|
||||
auto pyramidFBO = framebufferCache->getDepthPyramidFramebuffer();
|
||||
auto occlusionFBO = framebufferCache->getDeferredFramebufferDepthColor();
|
||||
auto occlusionFBO = framebufferCache->getOcclusionFramebuffer();
|
||||
auto occlusionBlurredFBO = framebufferCache->getOcclusionBlurredFramebuffer();
|
||||
auto occlusionFinalFBO = framebufferCache->getDeferredFramebufferDepthColor();
|
||||
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
||||
|
@ -536,7 +370,9 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
|
||||
auto pyramidPipeline = getPyramidPipeline();
|
||||
auto occlusionPipeline = getOcclusionPipeline();
|
||||
|
||||
auto firstHBlurPipeline = getHBlurPipeline();
|
||||
auto lastVBlurPipeline = getVBlurPipeline();
|
||||
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
|
@ -557,11 +393,12 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
|
||||
// Pyramid pass
|
||||
batch.setFramebuffer(pyramidFBO);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(args->_viewFrustum->getFarClip(), 0.0f, 0.0f, 0.0f));
|
||||
batch.setPipeline(pyramidPipeline);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_DepthMapSlot, depthBuffer);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
//
|
||||
// Make pyramid mips
|
||||
batch.setFramebuffer(occlusionFBO);
|
||||
batch.generateTextureMips(pyramidFBO->getRenderBuffer(0));
|
||||
|
||||
|
@ -570,5 +407,16 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext
|
|||
batch.setResourceTexture(AmbientOcclusionEffect_PyramidMapSlot, pyramidFBO->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
// Blur 1 pass
|
||||
batch.setFramebuffer(occlusionBlurredFBO);
|
||||
batch.setPipeline(firstHBlurPipeline);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionFBO->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
// Blur 2 pass
|
||||
batch.setFramebuffer(occlusionFinalFBO);
|
||||
batch.setPipeline(lastVBlurPipeline);
|
||||
batch.setResourceTexture(AmbientOcclusionEffect_OcclusionMapSlot, occlusionBlurredFBO->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ public:
|
|||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
typedef render::Job::Model<AmbientOcclusionEffect> JobModel;
|
||||
|
||||
void setRadius(float radius);
|
||||
float getRadius() const { return _parametersBuffer.get<Parameters>()._radius_radius2_InvRadius6_s2.x; }
|
||||
|
||||
private:
|
||||
|
||||
void setClipInfo(float nearZ, float farZ);
|
||||
|
@ -33,7 +36,7 @@ private:
|
|||
public:
|
||||
glm::vec4 _clipInfo;
|
||||
glm::mat4 _projection;
|
||||
glm::vec4 _radius_s0_s1_s2{ 0.5, 0.0, 0.0, 0.0 };
|
||||
glm::vec4 _radius_radius2_InvRadius6_s2{ 0.5, 0.5 * 0.5, 1.0 / (0.25 * 0.25 * 0.25), 0.0 };
|
||||
|
||||
Parameters() {}
|
||||
};
|
||||
|
@ -56,8 +59,8 @@ private:
|
|||
|
||||
const gpu::PipelinePointer& getPyramidPipeline();
|
||||
const gpu::PipelinePointer& getOcclusionPipeline();
|
||||
const gpu::PipelinePointer& getHBlurPipeline();
|
||||
const gpu::PipelinePointer& getVBlurPipeline();
|
||||
const gpu::PipelinePointer& getHBlurPipeline(); // first
|
||||
const gpu::PipelinePointer& getVBlurPipeline(); // second
|
||||
|
||||
gpu::PipelinePointer _pyramidPipeline;
|
||||
gpu::PipelinePointer _occlusionPipeline;
|
||||
|
|
|
@ -32,7 +32,9 @@ enum Slots {
|
|||
Specular,
|
||||
Depth,
|
||||
Lighting,
|
||||
Pyramid
|
||||
Pyramid,
|
||||
OcclusionRaw,
|
||||
OcclusionBlurred
|
||||
};
|
||||
|
||||
static const std::string DEEFAULT_DIFFUSE_SHADER {
|
||||
|
@ -40,7 +42,7 @@ static const std::string DEEFAULT_DIFFUSE_SHADER {
|
|||
" return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_ALPHA_SHADER {
|
||||
static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(diffuseMap, uv).a), 1.0);"
|
||||
" }"
|
||||
|
@ -70,12 +72,23 @@ static const std::string DEEFAULT_LIGHTING_SHADER {
|
|||
" return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEFAULT_AMBIENT_OCCLUSION_SHADER {
|
||||
static const std::string DEFAULT_PYRAMID_DEPTH_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(1.0 - texture(pyramidMap, uv).x * 0.01), 1.0);"
|
||||
//" return vec4(vec3(1.0 - textureLod(pyramidMap, uv, 3).x * 0.01), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEFAULT_OCCLUSION_RAW_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(occlusionRawMap, uv).x), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEFAULT_OCCLUSION_BLURRED_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(occlusionBlurredMap, uv).x), 1.0);"
|
||||
" }"
|
||||
};
|
||||
|
||||
static const std::string DEEFAULT_CUSTOM_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(1.0, 0.0, 0.0, 1.0);"
|
||||
|
@ -106,8 +119,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus
|
|||
switch (mode) {
|
||||
case DiffuseMode:
|
||||
return DEEFAULT_DIFFUSE_SHADER;
|
||||
case AlphaMode:
|
||||
return DEEFAULT_ALPHA_SHADER;
|
||||
case AmbientOcclusionMode:
|
||||
return DEFAULT_AMBIENT_OCCLUSION_SHADER;
|
||||
case SpecularMode:
|
||||
return DEEFAULT_SPECULAR_SHADER;
|
||||
case RoughnessMode:
|
||||
|
@ -118,8 +131,12 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string cus
|
|||
return DEEFAULT_DEPTH_SHADER;
|
||||
case LightingMode:
|
||||
return DEEFAULT_LIGHTING_SHADER;
|
||||
case AmbientOcclusionMode:
|
||||
return DEFAULT_AMBIENT_OCCLUSION_SHADER;
|
||||
case PyramidDepthMode:
|
||||
return DEFAULT_PYRAMID_DEPTH_SHADER;
|
||||
case OcclusionRawMode:
|
||||
return DEFAULT_OCCLUSION_RAW_SHADER;
|
||||
case OcclusionBlurredMode:
|
||||
return DEFAULT_OCCLUSION_BLURRED_SHADER;
|
||||
case CustomMode:
|
||||
return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER);
|
||||
}
|
||||
|
@ -168,6 +185,8 @@ const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::st
|
|||
slotBindings.insert(gpu::Shader::Binding("depthMap", Depth));
|
||||
slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting));
|
||||
slotBindings.insert(gpu::Shader::Binding("pyramidMap", Pyramid));
|
||||
slotBindings.insert(gpu::Shader::Binding("occlusionRawMap", OcclusionRaw));
|
||||
slotBindings.insert(gpu::Shader::Binding("occlusionBlurredMap", OcclusionBlurred));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto pipeline = gpu::Pipeline::create(program, std::make_shared<gpu::State>());
|
||||
|
@ -216,6 +235,8 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
|||
batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture());
|
||||
batch.setResourceTexture(Pyramid, framebufferCache->getDepthPyramidTexture());
|
||||
batch.setResourceTexture(OcclusionRaw, framebufferCache->getOcclusionTexture());
|
||||
batch.setResourceTexture(OcclusionBlurred, framebufferCache->getOcclusionBlurredTexture());
|
||||
|
||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y);
|
||||
|
|
|
@ -27,13 +27,15 @@ public:
|
|||
private:
|
||||
enum Modes : uint8_t {
|
||||
DiffuseMode = 0,
|
||||
AlphaMode,
|
||||
AmbientOcclusionMode,
|
||||
SpecularMode,
|
||||
RoughnessMode,
|
||||
NormalMode,
|
||||
DepthMode,
|
||||
LightingMode,
|
||||
AmbientOcclusionMode,
|
||||
PyramidDepthMode,
|
||||
OcclusionRawMode,
|
||||
OcclusionBlurredMode,
|
||||
|
||||
CustomMode // Needs to stay last
|
||||
};
|
||||
|
|
|
@ -47,6 +47,10 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
_lightingFramebuffer.reset();
|
||||
_depthPyramidFramebuffer.reset();
|
||||
_depthPyramidTexture.reset();
|
||||
_occlusionFramebuffer.reset();
|
||||
_occlusionTexture.reset();
|
||||
_occlusionBlurredFramebuffer.reset();
|
||||
_occlusionBlurredTexture.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +109,18 @@ void FramebufferCache::createPrimaryFramebuffer() {
|
|||
_depthPyramidFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_depthPyramidFramebuffer->setRenderBuffer(0, _depthPyramidTexture);
|
||||
_depthPyramidFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
|
||||
_occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler));
|
||||
_occlusionFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_occlusionFramebuffer->setRenderBuffer(0, _occlusionTexture);
|
||||
_occlusionFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
|
||||
_occlusionBlurredTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGB), width, height, defaultSampler));
|
||||
_occlusionBlurredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_occlusionBlurredFramebuffer->setRenderBuffer(0, _occlusionBlurredTexture);
|
||||
_occlusionBlurredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
}
|
||||
|
||||
|
@ -220,4 +236,32 @@ gpu::TexturePointer FramebufferCache::getDepthPyramidTexture() {
|
|||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _depthPyramidTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getOcclusionFramebuffer() {
|
||||
if (!_occlusionFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _occlusionFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getOcclusionTexture() {
|
||||
if (!_occlusionTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _occlusionTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getOcclusionBlurredFramebuffer() {
|
||||
if (!_occlusionBlurredFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _occlusionBlurredFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getOcclusionBlurredTexture() {
|
||||
if (!_occlusionBlurredTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _occlusionBlurredTexture;
|
||||
}
|
|
@ -43,6 +43,12 @@ public:
|
|||
|
||||
gpu::FramebufferPointer getDepthPyramidFramebuffer();
|
||||
gpu::TexturePointer getDepthPyramidTexture();
|
||||
|
||||
gpu::FramebufferPointer getOcclusionFramebuffer();
|
||||
gpu::TexturePointer getOcclusionTexture();
|
||||
gpu::FramebufferPointer getOcclusionBlurredFramebuffer();
|
||||
gpu::TexturePointer getOcclusionBlurredTexture();
|
||||
|
||||
|
||||
gpu::TexturePointer getLightingTexture();
|
||||
gpu::FramebufferPointer getLightingFramebuffer();
|
||||
|
@ -87,6 +93,13 @@ private:
|
|||
|
||||
gpu::FramebufferPointer _depthPyramidFramebuffer;
|
||||
gpu::TexturePointer _depthPyramidTexture;
|
||||
|
||||
|
||||
gpu::FramebufferPointer _occlusionFramebuffer;
|
||||
gpu::TexturePointer _occlusionTexture;
|
||||
|
||||
gpu::FramebufferPointer _occlusionBlurredFramebuffer;
|
||||
gpu::TexturePointer _occlusionBlurredTexture;
|
||||
|
||||
QSize _frameBufferSize{ 100, 100 };
|
||||
};
|
||||
|
|
|
@ -158,12 +158,16 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
|
|||
|
||||
// TODO: turn on/off AO through menu item
|
||||
setOcclusionStatus(renderContext->getOcclusionStatus());
|
||||
|
||||
if (_occlusionJobIndex >= 0) {
|
||||
_jobs[_occlusionJobIndex].edit<AmbientOcclusionEffect>().setRadius(renderContext->getAmbientOcclusion().radius);
|
||||
}
|
||||
|
||||
setAntialiasingStatus(renderContext->getFxaaStatus());
|
||||
|
||||
setToneMappingExposure(renderContext->getTone().exposure);
|
||||
setToneMappingToneCurve(renderContext->getTone().toneCurve);
|
||||
|
||||
|
||||
renderContext->getArgs()->_context->syncCache();
|
||||
|
||||
for (auto job : _jobs) {
|
||||
|
|
|
@ -42,7 +42,7 @@ QString RenderScripting::Tone::getCurve() const {
|
|||
|
||||
render::RenderContext RenderScriptingInterface::getRenderContext() {
|
||||
render::RenderContext::ItemsConfig items{ *_opaque, *_transparent, *_overlay3D };
|
||||
return render::RenderContext{ items, *_tone, _drawStatus, _drawHitEffect, _deferredDebugSize, _deferredDebugMode };
|
||||
return render::RenderContext{ items, *_tone, *_ambientOcclusion, _drawStatus, _drawHitEffect, _deferredDebugSize, _deferredDebugMode };
|
||||
}
|
||||
|
||||
void RenderScriptingInterface::setItemCounts(const render::RenderContext::ItemsConfig& items) {
|
||||
|
|
|
@ -65,6 +65,14 @@ namespace RenderScripting {
|
|||
void setCurve(const QString& curve);
|
||||
};
|
||||
using TonePointer = std::unique_ptr<Tone>;
|
||||
|
||||
class AmbientOcclusion : public QObject, public render::RenderContext::AmbientOcclusion {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(float radius MEMBER radius)
|
||||
};
|
||||
using AmbientOcclusionPointer = std::unique_ptr<AmbientOcclusion>;
|
||||
};
|
||||
|
||||
class RenderScriptingInterface : public QObject, public Dependency {
|
||||
|
@ -77,7 +85,8 @@ class RenderScriptingInterface : public QObject, public Dependency {
|
|||
Q_PROPERTY(RenderScripting::ItemCounter* overlay3D READ getOverlay3D)
|
||||
|
||||
Q_PROPERTY(RenderScripting::Tone* tone READ getTone)
|
||||
|
||||
Q_PROPERTY(RenderScripting::AmbientOcclusion* ambientOcclusion READ getAmbientOcclusion)
|
||||
|
||||
Q_PROPERTY(int displayItemStatus MEMBER _drawStatus)
|
||||
Q_PROPERTY(bool displayHitEffect MEMBER _drawHitEffect)
|
||||
|
||||
|
@ -96,12 +105,15 @@ protected:
|
|||
RenderScripting::ItemCounter* getOverlay3D() const { return _overlay3D.get(); }
|
||||
|
||||
RenderScripting::Tone* getTone() const { return _tone.get(); }
|
||||
RenderScripting::AmbientOcclusion* getAmbientOcclusion() const { return _ambientOcclusion.get(); }
|
||||
|
||||
RenderScripting::ItemStatePointer _opaque = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}};
|
||||
RenderScripting::ItemStatePointer _transparent = RenderScripting::ItemStatePointer{new RenderScripting::ItemState{}};
|
||||
RenderScripting::ItemCounterPointer _overlay3D = RenderScripting::ItemCounterPointer{new RenderScripting::ItemCounter{}};
|
||||
|
||||
RenderScripting::TonePointer _tone = RenderScripting::TonePointer{ new RenderScripting::Tone{} };
|
||||
|
||||
RenderScripting::AmbientOcclusionPointer _ambientOcclusion = RenderScripting::AmbientOcclusionPointer{ new RenderScripting::AmbientOcclusion{} };
|
||||
|
||||
// Options
|
||||
int _drawStatus = 0;
|
||||
|
|
|
@ -1,279 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// ambient_occlusion.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/15/15.
|
||||
// Copyright 2015 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 DeferredBufferWrite.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
// Based on NVidia HBAO implementation in D3D11
|
||||
// http://www.nvidia.co.uk/object/siggraph-2008-HBAO.html
|
||||
|
||||
in vec2 varTexcoord;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
uniform sampler2D normalTexture;
|
||||
|
||||
uniform float g_scale;
|
||||
uniform float g_bias;
|
||||
uniform float g_sample_rad;
|
||||
uniform float g_intensity;
|
||||
|
||||
// the distance to the near clip plane
|
||||
uniform float near;
|
||||
|
||||
// scale factor for depth: (far - near) / far
|
||||
uniform float depthScale;
|
||||
|
||||
// offset for depth texture coordinates
|
||||
uniform vec2 depthTexCoordOffset;
|
||||
|
||||
// scale for depth texture coordinates
|
||||
uniform vec2 depthTexCoordScale;
|
||||
|
||||
// the resolution of the occlusion buffer
|
||||
// and its inverse
|
||||
uniform vec2 renderTargetRes;
|
||||
uniform vec2 renderTargetResInv;
|
||||
|
||||
|
||||
|
||||
const float PI = 3.14159265;
|
||||
|
||||
const float AOStrength = 1.9;
|
||||
|
||||
|
||||
// TODO: R (radius) should be exposed as a uniform parameter
|
||||
const float R = 0.01;
|
||||
const float R2 = 0.01*0.01;
|
||||
const float NegInvR2 = - 1.0 / (0.01*0.01);
|
||||
|
||||
|
||||
|
||||
// can't use tan to initialize a const value
|
||||
const float TanBias = 0.57735027; // tan(30.0 * PI / 180.0);
|
||||
const float MaxRadiusPixels = 50.0;
|
||||
|
||||
const int NumDirections = 6;
|
||||
const int NumSamples = 4;
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
/**
|
||||
* Gets the normal in view space from a normal texture.
|
||||
* uv: the uv texture coordinates to look up in the texture at.
|
||||
*/
|
||||
vec3 GetViewNormalFromTexture(vec2 uv) {
|
||||
// convert [0,1] -> [-1,1], note: since we're normalizing
|
||||
// we don't need to do v*2 - 1.0, we can just do a v-0.5
|
||||
return normalize(texture(normalTexture, uv).xyz - 0.5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the linearized depth in view space.
|
||||
* d: the depth value [0-1], usually from a depth texture to convert.
|
||||
*/
|
||||
float ViewSpaceZFromDepth(float d){
|
||||
return near / (d * depthScale - 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a uv coordinate and depth value into a 3D view space coordinate.
|
||||
* uv: the uv coordinates to convert
|
||||
* z: the view space depth of the uv coordinate.
|
||||
*/
|
||||
vec3 UVToViewSpace(vec2 uv, float z){
|
||||
return vec3((depthTexCoordOffset + varTexcoord * depthTexCoordScale) * z, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a uv coordinate into a 3D view space coordinate.
|
||||
* The depth of the uv coord is determined from the depth texture.
|
||||
* uv: the uv coordinates to convert
|
||||
*/
|
||||
vec3 GetViewPos(vec2 uv) {
|
||||
float z = ViewSpaceZFromDepth(texture(depthTexture, uv).r);
|
||||
return UVToViewSpace(uv, z);
|
||||
}
|
||||
|
||||
|
||||
float TanToSin(float x) {
|
||||
return x * inversesqrt(x*x + 1.0);
|
||||
}
|
||||
|
||||
float InvLength(vec2 V) {
|
||||
return inversesqrt(dot(V, V));
|
||||
}
|
||||
|
||||
float Tangent(vec3 V) {
|
||||
return V.z * InvLength(V.xy);
|
||||
}
|
||||
|
||||
float BiasedTangent(vec3 V) {
|
||||
return V.z * InvLength(V.xy) + TanBias;
|
||||
}
|
||||
|
||||
float Tangent(vec3 P, vec3 S) {
|
||||
return -(P.z - S.z) * InvLength(S.xy - P.xy);
|
||||
}
|
||||
|
||||
float Length2(vec3 V) {
|
||||
return dot(V, V);
|
||||
}
|
||||
|
||||
vec3 MinDiff(vec3 P, vec3 Pr, vec3 Pl) {
|
||||
vec3 V1 = Pr - P;
|
||||
vec3 V2 = P - Pl;
|
||||
return (Length2(V1) < Length2(V2)) ? V1 : V2;
|
||||
}
|
||||
|
||||
vec2 SnapUVOffset(vec2 uv) {
|
||||
return round(uv * renderTargetRes) * renderTargetResInv;
|
||||
}
|
||||
|
||||
float Falloff(float d2) {
|
||||
return d2 * NegInvR2 + 1.0f;
|
||||
}
|
||||
|
||||
float HorizonOcclusion(vec2 deltaUV, vec3 P, vec3 dPdu, vec3 dPdv, float randstep, float numSamples) {
|
||||
float ao = 0;
|
||||
|
||||
// Offset the first coord with some noise
|
||||
vec2 uv = varTexcoord + SnapUVOffset(randstep*deltaUV);
|
||||
deltaUV = SnapUVOffset(deltaUV);
|
||||
|
||||
// Calculate the tangent vector
|
||||
vec3 T = deltaUV.x * dPdu + deltaUV.y * dPdv;
|
||||
|
||||
// Get the angle of the tangent vector from the viewspace axis
|
||||
float tanH = BiasedTangent(T);
|
||||
float sinH = TanToSin(tanH);
|
||||
|
||||
float tanS;
|
||||
float d2;
|
||||
vec3 S;
|
||||
|
||||
// Sample to find the maximum angle
|
||||
for (float s = 1; s <= numSamples; ++s) {
|
||||
uv += deltaUV;
|
||||
S = GetViewPos(uv);
|
||||
tanS = Tangent(P, S);
|
||||
d2 = Length2(S - P);
|
||||
|
||||
// Is the sample within the radius and the angle greater?
|
||||
if (d2 < R2 && tanS > tanH) {
|
||||
float sinS = TanToSin(tanS);
|
||||
// Apply falloff based on the distance
|
||||
ao += Falloff(d2) * (sinS - sinH);
|
||||
|
||||
tanH = tanS;
|
||||
sinH = sinS;
|
||||
}
|
||||
}
|
||||
return ao;
|
||||
}
|
||||
|
||||
vec2 RotateDirections(vec2 Dir, vec2 CosSin) {
|
||||
return vec2(Dir.x*CosSin.x - Dir.y*CosSin.y,
|
||||
Dir.x*CosSin.y + Dir.y*CosSin.x);
|
||||
}
|
||||
|
||||
void ComputeSteps(inout vec2 stepSizeUv, inout float numSteps, float rayRadiusPix, float rand) {
|
||||
// Avoid oversampling if numSteps is greater than the kernel radius in pixels
|
||||
numSteps = min(NumSamples, rayRadiusPix);
|
||||
|
||||
// Divide by Ns+1 so that the farthest samples are not fully attenuated
|
||||
float stepSizePix = rayRadiusPix / (numSteps + 1);
|
||||
|
||||
// Clamp numSteps if it is greater than the max kernel footprint
|
||||
float maxNumSteps = MaxRadiusPixels / stepSizePix;
|
||||
if (maxNumSteps < numSteps) {
|
||||
// Use dithering to avoid AO discontinuities
|
||||
numSteps = floor(maxNumSteps + rand);
|
||||
numSteps = max(numSteps, 1);
|
||||
stepSizePix = MaxRadiusPixels / numSteps;
|
||||
}
|
||||
|
||||
// Step size in uv space
|
||||
stepSizeUv = stepSizePix * renderTargetResInv;
|
||||
}
|
||||
|
||||
float getRandom(vec2 uv) {
|
||||
return fract(sin(dot(uv.xy ,vec2(12.9898,78.233))) * 43758.5453);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
mat4 projMatrix = getTransformCamera()._projection;
|
||||
|
||||
float numDirections = NumDirections;
|
||||
|
||||
vec3 P, Pr, Pl, Pt, Pb;
|
||||
P = GetViewPos(varTexcoord);
|
||||
|
||||
// Sample neighboring pixels
|
||||
Pr = GetViewPos(varTexcoord + vec2( renderTargetResInv.x, 0));
|
||||
Pl = GetViewPos(varTexcoord + vec2(-renderTargetResInv.x, 0));
|
||||
Pt = GetViewPos(varTexcoord + vec2( 0, renderTargetResInv.y));
|
||||
Pb = GetViewPos(varTexcoord + vec2( 0,-renderTargetResInv.y));
|
||||
|
||||
// Calculate tangent basis vectors using the minimum difference
|
||||
vec3 dPdu = MinDiff(P, Pr, Pl);
|
||||
vec3 dPdv = MinDiff(P, Pt, Pb) * (renderTargetRes.y * renderTargetResInv.x);
|
||||
|
||||
// Get the random samples from the noise function
|
||||
vec3 random = vec3(getRandom(varTexcoord.xy), getRandom(varTexcoord.yx), getRandom(varTexcoord.xx));
|
||||
|
||||
// Calculate the projected size of the hemisphere
|
||||
float w = P.z * projMatrix[2][3] + projMatrix[3][3];
|
||||
vec2 rayRadiusUV = (0.5 * R * vec2(projMatrix[0][0], projMatrix[1][1]) / w); // [-1,1] -> [0,1] uv
|
||||
float rayRadiusPix = rayRadiusUV.x * renderTargetRes.x;
|
||||
|
||||
float ao = 1.0;
|
||||
|
||||
// Make sure the radius of the evaluated hemisphere is more than a pixel
|
||||
if(rayRadiusPix > 1.0) {
|
||||
ao = 0.0;
|
||||
float numSteps;
|
||||
vec2 stepSizeUV;
|
||||
|
||||
// Compute the number of steps
|
||||
ComputeSteps(stepSizeUV, numSteps, rayRadiusPix, random.z);
|
||||
|
||||
float alpha = 2.0 * PI / numDirections;
|
||||
|
||||
// Calculate the horizon occlusion of each direction
|
||||
for(float d = 0; d < numDirections; ++d) {
|
||||
float theta = alpha * d;
|
||||
|
||||
// Apply noise to the direction
|
||||
vec2 dir = RotateDirections(vec2(cos(theta), sin(theta)), random.xy);
|
||||
vec2 deltaUV = dir * stepSizeUV;
|
||||
|
||||
// Sample the pixels along the direction
|
||||
ao += HorizonOcclusion( deltaUV,
|
||||
P,
|
||||
dPdu,
|
||||
dPdv,
|
||||
random.z,
|
||||
numSteps);
|
||||
}
|
||||
|
||||
// Average the results and produce the final AO
|
||||
ao = 1.0 - ao / numDirections * AOStrength;
|
||||
}
|
||||
|
||||
|
||||
outFragColor = vec4(vec3(ao), 1.0);
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// ambient_occlusion.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/15/15.
|
||||
// Copyright 2015 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/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varTexcoord;
|
||||
|
||||
void main(void) {
|
||||
varTexcoord = inTexCoord0.xy;
|
||||
gl_Position = inPosition;
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
<@include DeferredBuffer.slh@>
|
||||
|
||||
uniform sampler2D pyramidMap;
|
||||
uniform sampler2D occlusionRawMap;
|
||||
uniform sampler2D occlusionBlurredMap;
|
||||
|
||||
in vec2 uv;
|
||||
out vec4 outFragColor;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// gaussian_blur.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/17/15.
|
||||
// Copyright 2015 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 DeferredBufferWrite.slh@>
|
||||
|
||||
// the interpolated normal
|
||||
//in vec4 interpolatedNormal;
|
||||
|
||||
in vec2 varTexcoord;
|
||||
in vec2 varBlurTexcoords[14];
|
||||
|
||||
uniform sampler2D occlusionTexture;
|
||||
|
||||
out vec4 outFragColor;
|
||||
void main(void) {
|
||||
outFragColor = vec4(0.0);
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[0])*0.0044299121055113265;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[1])*0.00895781211794;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[2])*0.0215963866053;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[3])*0.0443683338718;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[4])*0.0776744219933;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[5])*0.115876621105;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[6])*0.147308056121;
|
||||
outFragColor += texture(occlusionTexture, varTexcoord)*0.159576912161;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[7])*0.147308056121;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[8])*0.115876621105;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[9])*0.0776744219933;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[10])*0.0443683338718;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[11])*0.0215963866053;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[12])*0.00895781211794;
|
||||
outFragColor += texture(occlusionTexture, varBlurTexcoords[13])*0.0044299121055113265;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// guassian_blur_horizontal.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/17/15.
|
||||
// Copyright 2015 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/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varTexcoord;
|
||||
out vec2 varBlurTexcoords[14];
|
||||
|
||||
void main(void) {
|
||||
varTexcoord = inTexCoord0.xy;
|
||||
gl_Position = inPosition;
|
||||
|
||||
varBlurTexcoords[0] = varTexcoord + vec2(-0.028, 0.0);
|
||||
varBlurTexcoords[1] = varTexcoord + vec2(-0.024, 0.0);
|
||||
varBlurTexcoords[2] = varTexcoord + vec2(-0.020, 0.0);
|
||||
varBlurTexcoords[3] = varTexcoord + vec2(-0.016, 0.0);
|
||||
varBlurTexcoords[4] = varTexcoord + vec2(-0.012, 0.0);
|
||||
varBlurTexcoords[5] = varTexcoord + vec2(-0.008, 0.0);
|
||||
varBlurTexcoords[6] = varTexcoord + vec2(-0.004, 0.0);
|
||||
varBlurTexcoords[7] = varTexcoord + vec2(0.004, 0.0);
|
||||
varBlurTexcoords[8] = varTexcoord + vec2(0.008, 0.0);
|
||||
varBlurTexcoords[9] = varTexcoord + vec2(0.012, 0.0);
|
||||
varBlurTexcoords[10] = varTexcoord + vec2(0.016, 0.0);
|
||||
varBlurTexcoords[11] = varTexcoord + vec2(0.020, 0.0);
|
||||
varBlurTexcoords[12] = varTexcoord + vec2(0.024, 0.0);
|
||||
varBlurTexcoords[13] = varTexcoord + vec2(0.028, 0.0);
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// guassian_blur_vertical.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/17/15.
|
||||
// Copyright 2015 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/Inputs.slh@>
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec2 varTexcoord;
|
||||
out vec2 varBlurTexcoords[14];
|
||||
|
||||
void main(void) {
|
||||
varTexcoord = inTexCoord0.xy;
|
||||
gl_Position = inPosition;
|
||||
|
||||
varBlurTexcoords[0] = varTexcoord + vec2(0.0, -0.028);
|
||||
varBlurTexcoords[1] = varTexcoord + vec2(0.0, -0.024);
|
||||
varBlurTexcoords[2] = varTexcoord + vec2(0.0, -0.020);
|
||||
varBlurTexcoords[3] = varTexcoord + vec2(0.0, -0.016);
|
||||
varBlurTexcoords[4] = varTexcoord + vec2(0.0, -0.012);
|
||||
varBlurTexcoords[5] = varTexcoord + vec2(0.0, -0.008);
|
||||
varBlurTexcoords[6] = varTexcoord + vec2(0.0, -0.004);
|
||||
varBlurTexcoords[7] = varTexcoord + vec2(0.0, 0.004);
|
||||
varBlurTexcoords[8] = varTexcoord + vec2(0.0, 0.008);
|
||||
varBlurTexcoords[9] = varTexcoord + vec2(0.0, 0.012);
|
||||
varBlurTexcoords[10] = varTexcoord + vec2(0.0, 0.016);
|
||||
varBlurTexcoords[11] = varTexcoord + vec2(0.0, 0.020);
|
||||
varBlurTexcoords[12] = varTexcoord + vec2(0.0, 0.024);
|
||||
varBlurTexcoords[13] = varTexcoord + vec2(0.0, 0.028);
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// occlusion_blend.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Niraj Venkat on 7/20/15.
|
||||
// Copyright 2015 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 DeferredBufferWrite.slh@>
|
||||
|
||||
in vec2 varTexcoord;
|
||||
out vec4 outFragColor;
|
||||
|
||||
uniform sampler2D blurredOcclusionTexture;
|
||||
|
||||
void main(void) {
|
||||
vec4 occlusionColor = texture(blurredOcclusionTexture, varTexcoord);
|
||||
|
||||
outFragColor = vec4(vec3(0.0), occlusionColor.r);
|
||||
|
||||
}
|
58
libraries/render-utils/src/ssao.slh
Normal file
58
libraries/render-utils/src/ssao.slh
Normal file
|
@ -0,0 +1,58 @@
|
|||
<!
|
||||
// AmbientOcclusion.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// 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
|
||||
!>
|
||||
<@if not SSAO_SLH@>
|
||||
<@def SSAO_SLH@>
|
||||
|
||||
<@func declareAmbientOcclusion()@>
|
||||
|
||||
struct AmbientOcclusionParams {
|
||||
vec4 _clipInfo;
|
||||
mat4 _projection;
|
||||
vec4 _radius_radius2_InvRadius6_s2;
|
||||
};
|
||||
|
||||
uniform ambientOcclusionParamsBuffer {
|
||||
AmbientOcclusionParams params;
|
||||
};
|
||||
|
||||
float getProjScale() {
|
||||
return 500.0; // this should be viewportHeight * Proj[1][1] / 2.0
|
||||
}
|
||||
|
||||
float getRadius() {
|
||||
return params._radius_radius2_InvRadius6_s2.x;
|
||||
}
|
||||
float getRadius2() {
|
||||
return params._radius_radius2_InvRadius6_s2.y;
|
||||
}
|
||||
float getInvRadius6() {
|
||||
return params._radius_radius2_InvRadius6_s2.z;
|
||||
}
|
||||
|
||||
float evalZeyeFromZdb(float depth) {
|
||||
return params._clipInfo.x / (depth * params._clipInfo.y + params._clipInfo.z);
|
||||
}
|
||||
|
||||
vec3 evalEyePositionFromZeye(float Zeye, vec2 texcoord) {
|
||||
// compute the view space position using the depth
|
||||
// basically manually pick the proj matrix components to do the inverse
|
||||
float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * params._projection[2][0] - params._projection[3][0]) / params._projection[0][0];
|
||||
float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * params._projection[2][1] - params._projection[3][1]) / params._projection[1][1];
|
||||
return vec3(Xe, Ye, Zeye);
|
||||
}
|
||||
|
||||
vec3 evalEyeNormal(vec3 C) {
|
||||
return normalize(cross(dFdy(C), dFdx(C)));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
||||
<@endif@>
|
23
libraries/render-utils/src/ssao_makeHorizontalBlur.slf
Normal file
23
libraries/render-utils/src/ssao_makeHorizontalBlur.slf
Normal file
|
@ -0,0 +1,23 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// 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@>
|
||||
<$declareAmbientOcclusion()$>
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D occlusionMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = texture(occlusionMap, varTexCoord0);
|
||||
}
|
162
libraries/render-utils/src/ssao_makeOcclusion.slf
Normal file
162
libraries/render-utils/src/ssao_makeOcclusion.slf
Normal file
|
@ -0,0 +1,162 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// 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@>
|
||||
<$declareAmbientOcclusion()$>
|
||||
|
||||
const int NUM_SAMPLES = 11;
|
||||
const float INV_NUM_SAMPLES = 1.0 / float(NUM_SAMPLES);
|
||||
const int NUM_SPIRAL_TURNS= 7;
|
||||
const int LOG_MAX_OFFSET = 3;
|
||||
const int MAX_MIP_LEVEL = 5;
|
||||
|
||||
// the depth pyramid texture
|
||||
uniform sampler2D pyramidMap;
|
||||
|
||||
float getZeye(vec2 texcoord) {
|
||||
return -texture(pyramidMap, texcoord, 0).x;
|
||||
}
|
||||
|
||||
vec3 evalEyePosition(vec2 texcoord) {
|
||||
float Zeye = getZeye(texcoord);
|
||||
return evalEyePositionFromZeye(Zeye, texcoord);
|
||||
}
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
/** Used for packing Z into the GB channels */
|
||||
float CSZToKey(float z) {
|
||||
return clamp(z * (1.0 / params._clipInfo.z), 0.0, 1.0);
|
||||
}
|
||||
|
||||
/** Used for packing Z into the GB channels */
|
||||
void packKey(float key, out vec2 p) {
|
||||
// Round to the nearest 1/256.0
|
||||
float temp = floor(key * 256.0);
|
||||
|
||||
// Integer part
|
||||
p.x = temp * (1.0 / 256.0);
|
||||
|
||||
// Fractional part
|
||||
p.y = key * 256.0 - temp;
|
||||
}
|
||||
|
||||
vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
|
||||
// Radius relative to ssR
|
||||
float alpha = float(sampleNumber + 0.5) * INV_NUM_SAMPLES;
|
||||
float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
|
||||
|
||||
ssR = alpha;
|
||||
return vec2(cos(angle), sin(angle));
|
||||
}
|
||||
|
||||
vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
|
||||
// Derivation:
|
||||
// mipLevel = floor(log(ssR / MAX_OFFSET));
|
||||
int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
|
||||
|
||||
ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
|
||||
|
||||
vec3 P;
|
||||
|
||||
// We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
|
||||
// Manually clamp to the texture size because texelFetch bypasses the texture unit
|
||||
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(pyramidMap, mipLevel) - ivec2(1));
|
||||
P.z = -texelFetch(pyramidMap, mipP, mipLevel).r;
|
||||
|
||||
// Offset to pixel center
|
||||
//P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
|
||||
|
||||
vec2 tapUV = (vec2(ssP) + vec2(0.5)) / textureSize(pyramidMap, 0);
|
||||
P = evalEyePositionFromZeye(P.z, tapUV);
|
||||
return P;
|
||||
}
|
||||
|
||||
float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle) {
|
||||
// Offset on the unit disk, spun for this pixel
|
||||
float ssR;
|
||||
vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
|
||||
ssR *= ssDiskRadius;
|
||||
|
||||
// The occluding point in camera space
|
||||
vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
|
||||
|
||||
vec3 v = Q - C;
|
||||
float vv = dot(v, v);
|
||||
float vn = dot(v, n_C);
|
||||
|
||||
const float bias = 0.01;
|
||||
const float epsilon = 0.01;
|
||||
float radius2 = getRadius2();
|
||||
|
||||
// A: From the HPG12 paper
|
||||
// Note large epsilon to avoid overdarkening within cracks
|
||||
// return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
|
||||
|
||||
// B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
|
||||
float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
|
||||
|
||||
// C: Medium contrast (which looks better at high radii), no division. Note that the
|
||||
// contribution still falls off with radius^2, but we've adjusted the rate in a way that is
|
||||
// more computationally efficient and happens to be aesthetically pleasing.
|
||||
// return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
|
||||
|
||||
// D: Low contrast, no division operation
|
||||
// return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
|
||||
}
|
||||
|
||||
vec3 debugValue(float f, float scale) {
|
||||
if (f < 0.0) {
|
||||
return vec3((scale + f) / scale, 0.0, 0.0);
|
||||
} else {
|
||||
return vec3(0.0, (scale - f) / scale, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// Pixel being shaded
|
||||
ivec2 ssC = ivec2(gl_FragCoord.xy);
|
||||
|
||||
vec3 Cp = evalEyePosition(varTexCoord0);
|
||||
|
||||
// packKey(CSZToKey(Cp.z), bilateralKey);
|
||||
|
||||
// Hash function used in the HPG12 AlchemyAO paper
|
||||
float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10;
|
||||
//float randomPatternRotationAngle = 0;
|
||||
|
||||
|
||||
vec3 Cn = evalEyeNormal(Cp);
|
||||
|
||||
// Choose the screen-space sample radius
|
||||
// proportional to the projected area of the sphere
|
||||
float ssDiskRadius = -getProjScale() * getRadius() / Cp.z;
|
||||
|
||||
float sum = 0.0;
|
||||
for (int i = 0; i < NUM_SAMPLES; ++i) {
|
||||
sum += sampleAO(ssC, Cp, Cn, ssDiskRadius, i, randomPatternRotationAngle);
|
||||
}
|
||||
|
||||
float A = max(0.0, 1.0 - sum * getInvRadius6() * 5.0 * INV_NUM_SAMPLES);
|
||||
|
||||
// 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(A, debugValue(Cn.y, 10));
|
||||
}
|
25
libraries/render-utils/src/ssao_makePyramid.slf
Normal file
25
libraries/render-utils/src/ssao_makePyramid.slf
Normal file
|
@ -0,0 +1,25 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// 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@>
|
||||
<$declareAmbientOcclusion()$>
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
float Zdb = texture(depthMap, varTexCoord0).x;
|
||||
float Zeye = -evalZeyeFromZdb(Zdb);
|
||||
outFragColor = vec4(Zeye, 0.0, 0.0, 1.0);
|
||||
}
|
23
libraries/render-utils/src/ssao_makeVerticalBlur.slf
Normal file
23
libraries/render-utils/src/ssao_makeVerticalBlur.slf
Normal file
|
@ -0,0 +1,23 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// 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@>
|
||||
<$declareAmbientOcclusion()$>
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D occlusionMap;
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = vec4(0.0, 0.0, 0.0, texture(occlusionMap, varTexCoord0).x);
|
||||
}
|
|
@ -13,11 +13,11 @@
|
|||
#include "DrawTask.h"
|
||||
using namespace render;
|
||||
|
||||
RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode)
|
||||
RenderContext::RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode)
|
||||
: _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize },
|
||||
_args{ nullptr },
|
||||
_drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect },
|
||||
_items{ items }, _tone{ tone } {}
|
||||
_items{ items }, _tone{ tone }, _ambientOcclusion{ ao } {}
|
||||
|
||||
void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) {
|
||||
_occlusionStatus = occlusion;
|
||||
|
|
|
@ -76,14 +76,20 @@ public:
|
|||
int toneCurve = 1; // Means just Gamma 2.2 correction
|
||||
float exposure = 0.0;
|
||||
};
|
||||
|
||||
class AmbientOcclusion {
|
||||
public:
|
||||
float radius = 0.5; // radius in meters of the AO effect
|
||||
};
|
||||
|
||||
RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);
|
||||
RenderContext() : RenderContext({}, {}, {}, {}, {}, {}) {};
|
||||
RenderContext(ItemsConfig items, Tone tone, AmbientOcclusion ao, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode);
|
||||
RenderContext() : RenderContext({}, {}, {}, {}, {}, {}, {}) {};
|
||||
|
||||
void setArgs(RenderArgs* args) { _args = args; }
|
||||
inline RenderArgs* getArgs() { return _args; }
|
||||
inline ItemsConfig& getItemsConfig() { return _items; }
|
||||
inline Tone& getTone() { return _tone; }
|
||||
inline AmbientOcclusion& getAmbientOcclusion() { return _ambientOcclusion; }
|
||||
inline int getDrawStatus() { return _drawStatus; }
|
||||
inline bool getDrawHitEffect() { return _drawHitEffect; }
|
||||
inline bool getOcclusionStatus() { return _occlusionStatus; }
|
||||
|
@ -105,6 +111,7 @@ protected:
|
|||
|
||||
ItemsConfig _items;
|
||||
Tone _tone;
|
||||
AmbientOcclusion _ambientOcclusion;
|
||||
};
|
||||
typedef std::shared_ptr<RenderContext> RenderContextPointer;
|
||||
|
||||
|
|
Loading…
Reference in a new issue