mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 15:00:36 +02:00
Basic ambient occlusion effect up and running; needs tweaking and
optimization.
This commit is contained in:
parent
772ddfadb1
commit
b41fa1e03c
6 changed files with 177 additions and 41 deletions
|
@ -11,6 +11,13 @@
|
||||||
// the depth texture
|
// the depth texture
|
||||||
uniform sampler2D depthTexture;
|
uniform sampler2D depthTexture;
|
||||||
|
|
||||||
|
// the random rotation texture
|
||||||
|
uniform sampler2D rotationTexture;
|
||||||
|
|
||||||
|
// the sample kernel containing the unit offset vectors
|
||||||
|
const int SAMPLE_KERNEL_SIZE = 16;
|
||||||
|
uniform vec3 sampleKernel[SAMPLE_KERNEL_SIZE];
|
||||||
|
|
||||||
// the distance to the near clip plane
|
// the distance to the near clip plane
|
||||||
uniform float near;
|
uniform float near;
|
||||||
|
|
||||||
|
@ -23,20 +30,37 @@ uniform vec2 leftBottom;
|
||||||
// the right and top edges of the view window
|
// the right and top edges of the view window
|
||||||
uniform vec2 rightTop;
|
uniform vec2 rightTop;
|
||||||
|
|
||||||
|
// the radius of the effect
|
||||||
|
uniform float radius;
|
||||||
|
|
||||||
|
// the scale for the noise texture
|
||||||
|
uniform vec2 noiseScale;
|
||||||
|
|
||||||
|
// given a texture coordinate, returns the 3D view space z coordinate
|
||||||
|
float texCoordToViewSpaceZ(vec2 texCoord) {
|
||||||
|
return (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far);
|
||||||
|
}
|
||||||
|
|
||||||
// given a texture coordinate, returns the 3D view space coordinate
|
// given a texture coordinate, returns the 3D view space coordinate
|
||||||
vec3 texCoordToViewSpace(vec2 texCoord) {
|
vec3 texCoordToViewSpace(vec2 texCoord) {
|
||||||
float z = (far * near) / (texture2D(depthTexture, texCoord).r * (far - near) - far);
|
float z = texCoordToViewSpaceZ(texCoord);
|
||||||
return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z);
|
return vec3(((texCoord * 2.0 - vec2(1.0, 1.0)) * (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
float ds = dFdx(gl_TexCoord[0].s);
|
vec3 rotationX = texture2D(rotationTexture, gl_TexCoord[0].st * noiseScale).rgb;
|
||||||
float dt = dFdy(gl_TexCoord[0].t);
|
vec3 rotationY = normalize(cross(rotationX, vec3(0.0, 0.0, 1.0)));
|
||||||
|
mat3 rotation = mat3(rotationX, rotationY, cross(rotationX, rotationY));
|
||||||
|
|
||||||
vec3 center = texCoordToViewSpace(gl_TexCoord[0].st);
|
vec3 center = texCoordToViewSpace(gl_TexCoord[0].st);
|
||||||
vec3 left = texCoordToViewSpace(gl_TexCoord[0].st - vec2(-ds, 0.0)) - center;
|
|
||||||
vec3 right = texCoordToViewSpace(gl_TexCoord[0].st - vec2(ds, 0.0)) - center;
|
float occlusion = 4.0;
|
||||||
vec3 up = texCoordToViewSpace(gl_TexCoord[0].st - vec2(0.0, dt)) - center;
|
for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) {
|
||||||
vec3 down = texCoordToViewSpace(gl_TexCoord[0].st - vec2(0.0, -dt)) - center;
|
vec3 offset = center + rotation * (radius * sampleKernel[i]);
|
||||||
float occlusion = 0.5 - (left.z / length(left) + right.z / length(right) + up.z / length(up) + down.z / length(down)) / 8.0;
|
vec4 projected = gl_ProjectionMatrix * vec4(offset, 1.0);
|
||||||
gl_FragColor = vec4(occlusion, occlusion, occlusion, 0.0);
|
float depth = texCoordToViewSpaceZ(projected.xy * 0.5 / projected.w + vec2(0.5, 0.5));
|
||||||
|
occlusion += 1.0 - step(offset.z, depth); // * step(abs(center.z - depth), radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = vec4(occlusion, occlusion, occlusion, 0.0) / 16.0;
|
||||||
}
|
}
|
||||||
|
|
14
interface/resources/shaders/ambient_occlusion.vert
Normal file
14
interface/resources/shaders/ambient_occlusion.vert
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// ambient_occlusion.vert
|
||||||
|
// vertex shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/16/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
gl_Position = gl_Vertex;
|
||||||
|
}
|
25
interface/resources/shaders/occlusion_blur.frag
Normal file
25
interface/resources/shaders/occlusion_blur.frag
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#version 120
|
||||||
|
|
||||||
|
//
|
||||||
|
// occlusion_blur.frag
|
||||||
|
// fragment shader
|
||||||
|
//
|
||||||
|
// Created by Andrzej Kapolka on 8/16/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// the original texture
|
||||||
|
uniform sampler2D originalTexture;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
float ds = dFdx(gl_TexCoord[0].s);
|
||||||
|
float dt = dFdy(gl_TexCoord[0].t);
|
||||||
|
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
sum += texture2D(originalTexture, gl_TexCoord[0].st +
|
||||||
|
vec2(ds, dt) * vec2(-2.0 + float(i), -2.0 + float(j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gl_FragColor = sum / 16.0;
|
||||||
|
}
|
|
@ -6,6 +6,13 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
|
#include <QOpenGLFramebufferObject>
|
||||||
|
|
||||||
|
#include <glm/gtc/random.hpp>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "AmbientOcclusionEffect.h"
|
#include "AmbientOcclusionEffect.h"
|
||||||
|
@ -14,61 +21,120 @@
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
#include "RenderUtil.h"
|
#include "RenderUtil.h"
|
||||||
|
|
||||||
|
const int ROTATION_WIDTH = 4;
|
||||||
|
const int ROTATION_HEIGHT = 4;
|
||||||
|
|
||||||
void AmbientOcclusionEffect::init() {
|
void AmbientOcclusionEffect::init() {
|
||||||
switchToResourcesParentIfRequired();
|
switchToResourcesParentIfRequired();
|
||||||
|
|
||||||
_program = new ProgramObject();
|
_occlusionProgram = new ProgramObject();
|
||||||
_program->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag");
|
_occlusionProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert");
|
||||||
_program->link();
|
_occlusionProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/ambient_occlusion.frag");
|
||||||
|
_occlusionProgram->link();
|
||||||
|
|
||||||
_nearLocation = _program->uniformLocation("near");
|
_blurProgram = new ProgramObject();
|
||||||
_farLocation = _program->uniformLocation("far");
|
_blurProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/ambient_occlusion.vert");
|
||||||
_leftBottomLocation = _program->uniformLocation("leftBottom");
|
_blurProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/occlusion_blur.frag");
|
||||||
_rightTopLocation = _program->uniformLocation("rightTop");
|
_blurProgram->link();
|
||||||
|
|
||||||
_program->bind();
|
_blurProgram->bind();
|
||||||
_program->setUniformValue("depthTexture", 0);
|
_blurProgram->setUniformValue("originalTexture", 0);
|
||||||
_program->release();
|
_blurProgram->release();
|
||||||
|
|
||||||
|
// create the sample kernel: an array of spherically distributed offset vectors
|
||||||
|
const int SAMPLE_KERNEL_SIZE = 16;
|
||||||
|
QVector3D sampleKernel[SAMPLE_KERNEL_SIZE];
|
||||||
|
for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) {
|
||||||
|
glm::vec3 vector = glm::ballRand(1.0f);
|
||||||
|
sampleKernel[i] = QVector3D(vector.x, vector.y, vector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
_occlusionProgram->bind();
|
||||||
|
_occlusionProgram->setUniformValue("depthTexture", 0);
|
||||||
|
_occlusionProgram->setUniformValue("rotationTexture", 1);
|
||||||
|
_occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE);
|
||||||
|
_occlusionProgram->setUniformValue("radius", 0.1f);
|
||||||
|
_occlusionProgram->release();
|
||||||
|
|
||||||
|
_nearLocation = _occlusionProgram->uniformLocation("near");
|
||||||
|
_farLocation = _occlusionProgram->uniformLocation("far");
|
||||||
|
_leftBottomLocation = _occlusionProgram->uniformLocation("leftBottom");
|
||||||
|
_rightTopLocation = _occlusionProgram->uniformLocation("rightTop");
|
||||||
|
_noiseScaleLocation = _occlusionProgram->uniformLocation("noiseScale");
|
||||||
|
|
||||||
|
// generate the random rotation texture
|
||||||
|
glGenTextures(1, &_rotationTextureID);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _rotationTextureID);
|
||||||
|
const int ELEMENTS_PER_PIXEL = 3;
|
||||||
|
unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL];
|
||||||
|
unsigned char* rotation = rotationData;
|
||||||
|
for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) {
|
||||||
|
glm::vec3 randvec = glm::sphericalRand(1.0f);
|
||||||
|
*rotation++ = ((randvec.x + 1.0f) / 2.0f) * 255.0f;
|
||||||
|
*rotation++ = ((randvec.y + 1.0f) / 2.0f) * 255.0f;
|
||||||
|
*rotation++ = ((randvec.z + 1.0f) / 2.0f) * 255.0f;
|
||||||
|
}
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AmbientOcclusionEffect::render() {
|
void AmbientOcclusionEffect::render() {
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
//glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID());
|
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID());
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _rotationTextureID);
|
||||||
|
|
||||||
|
// render with the occlusion shader to the secondary buffer
|
||||||
|
QOpenGLFramebufferObject* secondaryFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject();
|
||||||
|
secondaryFBO->bind();
|
||||||
|
|
||||||
float left, right, bottom, top, nearVal, farVal;
|
float left, right, bottom, top, nearVal, farVal;
|
||||||
glm::vec4 nearClipPlane, farClipPlane;
|
glm::vec4 nearClipPlane, farClipPlane;
|
||||||
Application::getInstance()->getViewFrustum()->computeOffAxisFrustum(
|
Application::getInstance()->getViewFrustum()->computeOffAxisFrustum(
|
||||||
left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
|
||||||
|
|
||||||
_program->bind();
|
_occlusionProgram->bind();
|
||||||
_program->setUniformValue(_nearLocation, nearVal);
|
_occlusionProgram->setUniformValue(_nearLocation, nearVal);
|
||||||
_program->setUniformValue(_farLocation, farVal);
|
_occlusionProgram->setUniformValue(_farLocation, farVal);
|
||||||
_program->setUniformValue(_leftBottomLocation, left, bottom);
|
_occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom);
|
||||||
_program->setUniformValue(_rightTopLocation, right, top);
|
_occlusionProgram->setUniformValue(_rightTopLocation, right, top);
|
||||||
|
QSize size = Application::getInstance()->getGLWidget()->size();
|
||||||
|
_occlusionProgram->setUniformValue(_noiseScaleLocation, size.width() / (float)ROTATION_WIDTH,
|
||||||
|
size.height() / (float)ROTATION_HEIGHT);
|
||||||
|
|
||||||
renderFullscreenQuad();
|
renderFullscreenQuad();
|
||||||
|
|
||||||
_program->release();
|
_occlusionProgram->release();
|
||||||
|
|
||||||
glPopMatrix();
|
secondaryFBO->release();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
// now render secondary to primary with 4x4 blur
|
||||||
|
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind();
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glPopMatrix();
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture());
|
||||||
|
|
||||||
|
_blurProgram->bind();
|
||||||
|
|
||||||
|
renderFullscreenQuad();
|
||||||
|
|
||||||
|
_blurProgram->release();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
//glEnable(GL_BLEND);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef __interface__AmbientOcclusionEffect__
|
#ifndef __interface__AmbientOcclusionEffect__
|
||||||
#define __interface__AmbientOcclusionEffect__
|
#define __interface__AmbientOcclusionEffect__
|
||||||
|
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
class ProgramObject;
|
class ProgramObject;
|
||||||
|
|
||||||
/// A screen space ambient occlusion effect.
|
/// A screen space ambient occlusion effect.
|
||||||
|
@ -21,11 +23,16 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
ProgramObject* _program;
|
ProgramObject* _occlusionProgram;
|
||||||
int _nearLocation;
|
int _nearLocation;
|
||||||
int _farLocation;
|
int _farLocation;
|
||||||
int _leftBottomLocation;
|
int _leftBottomLocation;
|
||||||
int _rightTopLocation;
|
int _rightTopLocation;
|
||||||
|
int _noiseScaleLocation;
|
||||||
|
|
||||||
|
ProgramObject* _blurProgram;
|
||||||
|
|
||||||
|
GLuint _rotationTextureID;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__AmbientOcclusionEffect__) */
|
#endif /* defined(__interface__AmbientOcclusionEffect__) */
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// Created by Andrzej Kapolka on 8/7/13.
|
// Created by Andrzej Kapolka on 8/7/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
|
||||||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
#include <QOpenGLFramebufferObject>
|
#include <QOpenGLFramebufferObject>
|
||||||
|
|
Loading…
Reference in a new issue