Skip to content

Commit

Permalink
Add basic SSAO
Browse files Browse the repository at this point in the history
It is not working as it should, consider it experimental at best.
  • Loading branch information
enginmanap committed Dec 10, 2018
1 parent 76ee172 commit adc4756
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 15 deletions.
61 changes: 55 additions & 6 deletions Engine/Shaders/Model/fragment.glsl
Expand Up @@ -7,7 +7,9 @@ layout (std140) uniform PlayerTransformBlock {
mat4 camera;
mat4 projection;
mat4 cameraProjection;
mat4 inverseTransposeProjection;
vec3 position;
vec2 noiseScale;
} playerTransforms;

struct LightSource
Expand Down Expand Up @@ -44,14 +46,16 @@ out vec4 finalColor;

uniform sampler2DArray shadowSamplerDirectional;
uniform samplerCubeArray shadowSamplerPoint;
uniform sampler2D ssaoSampler;
uniform sampler2D ssaoNoiseSampler;

uniform sampler2D ambientSampler;
uniform sampler2D diffuseSampler;
uniform sampler2D specularSampler;
uniform sampler2D opacitySampler;
uniform sampler2D normalSampler;

uniform vec3 pointSampleOffsetDirections[20] = vec3[]
vec3 pointSampleOffsetDirections[20] = vec3[]
(
vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
Expand All @@ -60,6 +64,9 @@ uniform vec3 pointSampleOffsetDirections[20] = vec3[]
vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1)
);

uniform vec3 ssaoKernel[128];
uniform int ssaoSampleCount;

float ShadowCalculationDirectional(vec4 fragPosLightSpace, float bias, float lightIndex){
// perform perspective divide
vec3 projectedCoordinates = fragPosLightSpace.xyz / fragPosLightSpace.w;
Expand Down Expand Up @@ -112,6 +119,13 @@ float ShadowCalculationPoint(vec3 fragPos, float bias, float viewDistance, int l
return shadow;
}

vec3 calcViewSpacePos(vec3 screen) {
vec4 temp = vec4(screen.x, screen.y, screen.z, 1);
temp *= playerTransforms.inverseTransposeProjection;
vec3 camera_space = temp.xyz / temp.w;
return camera_space;
}

void main(void) {
vec4 objectColor;
if((material.isMap & 0x0004)!=0) {
Expand All @@ -132,16 +146,51 @@ void main(void) {
objectColor = vec4(material.diffuse, 1.0);
}

vec3 lightingColorFactor = material.ambient;
if((material.isMap & 0x0008)!=0) {
lightingColorFactor = vec3(texture(ambientSampler, from_vs.textureCoord));
}

vec3 normal = from_vs.normal;

if((material.isMap & 0x0010) != 0) {
normal = -1 * vec3(texture(normalSampler, from_vs.textureCoord));
}

float occlusion = 0.0;

if(length(playerTransforms.position - from_vs.fragPos) < 100) {
vec3 randomVec = texture(ssaoNoiseSampler, from_vs.fragPos.xy * playerTransforms.noiseScale).xyz;

vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);

float uRadius = 0.5f;
for(int i = 0; i < ssaoSampleCount; ++i){
// get sample position
vec3 samplePosition = TBN * ssaoKernel[i]; // From tangent to view-space
samplePosition = samplePosition * uRadius;
samplePosition += vec3(from_vs.fragPos);

vec4 offset = vec4(samplePosition, 1.0);
offset = playerTransforms.cameraProjection * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0

float sampleDepth = texture(ssaoSampler, offset.xy).r;

vec3 realElement = calcViewSpacePos(vec3(offset.xy, sampleDepth));
vec3 kernelElement = calcViewSpacePos(offset.xyz);

float rangeCheck= abs(realElement.z - kernelElement.z) < 1 ? 1.0 : 0.0;
occlusion += (realElement.z >= kernelElement.z ? 1.0 : 0.0) * rangeCheck;
}

occlusion = occlusion / ssaoSampleCount;
}
occlusion = 1 - occlusion;

vec3 lightingColorFactor = (material.ambient) * occlusion;
if((material.isMap & 0x0008)!=0) {
lightingColorFactor = vec3(texture(ambientSampler, from_vs.textureCoord));
}

float shadow;
for(int i=0; i < NR_POINT_LIGHTS; ++i){
if(LightSources.lights[i].type != 0) {
Expand Down
2 changes: 2 additions & 0 deletions Engine/Shaders/Model/vertex.glsl
Expand Up @@ -19,7 +19,9 @@ layout (std140) uniform PlayerTransformBlock {
mat4 camera;
mat4 projection;
mat4 cameraProjection;
mat4 inverseTransposeProjection;
vec3 position;
vec2 noiseScale;
} playerTransforms;

struct LightSource
Expand Down
2 changes: 2 additions & 0 deletions Engine/Shaders/Model/vertexAnimated.glsl
Expand Up @@ -23,7 +23,9 @@ layout (std140) uniform PlayerTransformBlock {
mat4 camera;
mat4 projection;
mat4 cameraProjection;
mat4 inverseTransposeProjection;
vec3 position;
vec2 noiseScale;
} playerTransforms;

struct LightSource
Expand Down
6 changes: 6 additions & 0 deletions Engine/Shaders/SSAO/fragment.glsl
@@ -0,0 +1,6 @@
#version 330 core
#define NR_POINT_LIGHTS 4

void main() {
//gl_FragDepth = FragPos.z;
}
43 changes: 43 additions & 0 deletions Engine/Shaders/SSAO/vertex.glsl
@@ -0,0 +1,43 @@
#version 330 core

#define NR_POINT_LIGHTS 4
#define NR_BONE 128
#define NR_MAX_MODELS 1000


layout (location = 2) in vec4 position;
layout (location = 5) in uvec4 boneIDs;
layout (location = 6) in vec4 boneWeights;

layout (std140) uniform PlayerTransformBlock {
mat4 camera;
mat4 projection;
mat4 cameraProjection;
mat4 inverseTransposeProjection;
vec3 position;
vec2 noiseScale;
} playerTransforms;

layout (std140) uniform ModelInformationBlock {
mat4 worldTransform[NR_MAX_MODELS];
} model;

layout (std140) uniform ModelIndexBlock {
uvec4 models[NR_MAX_MODELS];
} instance;

uniform mat4 boneTransformArray[NR_BONE];
uniform int isAnimated;

void main() {
if(isAnimated==1) {
mat4 BoneTransform = mat4(1.0);
BoneTransform = boneTransformArray[boneIDs[0]] * boneWeights[0];
BoneTransform += boneTransformArray[boneIDs[1]] * boneWeights[1];
BoneTransform += boneTransformArray[boneIDs[2]] * boneWeights[2];
BoneTransform += boneTransformArray[boneIDs[3]] * boneWeights[3];
gl_Position = playerTransforms.cameraProjection * (model.worldTransform[instance.models[gl_InstanceID].x] * (BoneTransform * vec4(vec3(position), 1.0)));
} else {
gl_Position = playerTransforms.cameraProjection * (model.worldTransform[instance.models[gl_InstanceID].x] * position);
}
}
74 changes: 68 additions & 6 deletions src/GLHelper.cpp
Expand Up @@ -2,6 +2,7 @@
// Created by Engin Manap on 10.02.2016.
//

#include <random>
#include "GLHelper.h"
#include "GLSLProgram.h"

Expand Down Expand Up @@ -222,6 +223,9 @@ void GLHelper::attachGeneralUBOs(const GLuint program){//Attach the light block


GLHelper::GLHelper(Options *options): options(options) {

this->screenHeight = options->getScreenHeight();
this->screenWidth = options->getScreenWidth();
GLenum rev;
error = GL_NO_ERROR;
glewExperimental = GL_TRUE;
Expand Down Expand Up @@ -389,8 +393,48 @@ GLHelper::GLHelper(Options *options): options(options) {
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);

glBindFramebuffer(GL_FRAMEBUFFER, 0);
checkErrors("Constructor bf ssao");

//create depth buffer for SSAO
glGenFramebuffers(1, &depthOnlyFrameBufferSSAO);
glGenTextures(1, &depthMapSSAO);
glBindTexture(GL_TEXTURE_2D, depthMapSSAO);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glBindTexture(GL_TEXTURE_2D, 0);

glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFrameBufferSSAO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMapSSAO, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

/****************************** SSAO KERNEL AND NOISE **************************************/
std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // generates random floats between 0.0 and 1.0
std::default_random_engine generator;
// generate noise texture
// ----------------------
std::vector<glm::vec3> ssaoNoise;
for (unsigned int i = 0; i < 16; i++)
{
glm::vec3 noise(randomFloats(generator) * 2.0 - 1.0, randomFloats(generator) * 2.0 - 1.0, 0.0f); // rotate around z-axis (in tangent space)
ssaoNoise.push_back(noise);
}
glGenTextures(1, &noiseTexture);
glBindTexture(GL_TEXTURE_2D, noiseTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
/****************************** SSAO KERNEL AND NOISE **************************************/

frustumPlanes.resize(6);

checkErrors("Constructor");
Expand Down Expand Up @@ -573,15 +617,25 @@ void GLHelper::switchRenderToShadowMapPoint() {
checkErrors("switchRenderToShadowMapPoint");
}

void GLHelper::switchRenderToSSAO() {
glViewport(0, 0, screenWidth, screenHeight);
glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFrameBufferSSAO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMapSSAO, 0);

glCullFace(GL_BACK);
checkErrors("switchRenderToSSAO");
}

void GLHelper::switchRenderToDefault() {
glViewport(0, 0, screenWidth, screenHeight);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//we bind shadow map to last texture unit
state->attach2DTextureArray(depthMapDirectional, maxTextureImageUnits - 1);
state->attachCubemapArray(depthCubemapPoint, maxTextureImageUnits - 2);
state->attachTexture(depthMapSSAO, maxTextureImageUnits - 3);
state->attachTexture(noiseTexture, maxTextureImageUnits - 4);

glCullFace(GL_BACK);
//glEnable(GL_CULL_FACE);
checkErrors("switchRenderToDefault");
}

Expand Down Expand Up @@ -722,7 +776,11 @@ GLHelper::~GLHelper() {
deleteBuffer(1, playerUBOLocation);
deleteBuffer(1, allMaterialsUBOLocation);
deleteBuffer(1, depthMapDirectional);
deleteBuffer(1, depthCubemapPoint);
deleteBuffer(1, depthMapSSAO);
glDeleteFramebuffers(1, &depthOnlyFrameBufferDirectional); //maybe we should wrap this up too
glDeleteFramebuffers(1, &depthOnlyFrameBufferPoint);
glDeleteFramebuffers(1, &depthOnlyFrameBufferSSAO);
//state->setProgram(0);
}

Expand All @@ -732,7 +790,8 @@ void GLHelper::reshape() {
this->screenWidth = options->getScreenWidth();
glViewport(0, 0, options->getScreenWidth(), options->getScreenHeight());
aspect = float(options->getScreenHeight()) / float(options->getScreenWidth());
perspectiveProjectionMatrix = glm::perspective(options->PI/3.0f, 1.0f / aspect, 0.01f, 1000.0f);
perspectiveProjectionMatrix = glm::perspective(options->PI/3.0f, 1.0f / aspect, 0.01f, 10000.0f);
inverseTransposeProjection = glm::transpose(glm::inverse(perspectiveProjectionMatrix));
orthogonalProjectionMatrix = glm::ortho(0.0f, (float) options->getScreenWidth(), 0.0f, (float) options->getScreenHeight());
checkErrors("reshape");
}
Expand Down Expand Up @@ -962,11 +1021,14 @@ void GLHelper::setModelIndexesUBO(std::vector<uint32_t> &modelIndicesList) {
void GLHelper::setPlayerMatrices(const glm::vec3 &cameraPosition, const glm::mat4 &cameraTransform) {
this->cameraMatrix = cameraTransform;
glBindBuffer(GL_UNIFORM_BUFFER, playerUBOLocation);
glBufferSubData(GL_UNIFORM_BUFFER, 0 * sizeof(glm::mat4), sizeof(glm::mat4), &cameraMatrix);//changes with camera
glBufferSubData(GL_UNIFORM_BUFFER, 1 * sizeof(glm::mat4), sizeof(glm::mat4), &perspectiveProjectionMatrix);//never changes
glBufferSubData(GL_UNIFORM_BUFFER, 0 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(cameraMatrix));//changes with camera
glBufferSubData(GL_UNIFORM_BUFFER, 1 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(perspectiveProjectionMatrix));//never changes
glm::mat4 viewMatrix = perspectiveProjectionMatrix * cameraMatrix;
glBufferSubData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), sizeof(glm::mat4), &viewMatrix);//changes with camera
glBufferSubData(GL_UNIFORM_BUFFER, 3 * sizeof(glm::mat4), sizeof(glm::vec3), &cameraPosition);//changes with camera
glBufferSubData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(viewMatrix));//changes with camera
glBufferSubData(GL_UNIFORM_BUFFER, 3 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(inverseTransposeProjection));//never changes
glBufferSubData(GL_UNIFORM_BUFFER, 4 * sizeof(glm::mat4), sizeof(glm::vec3), glm::value_ptr(cameraPosition));//changes with camera
glm::vec2 noiseScale(this->screenWidth / 4, this->screenHeight / 4);
glBufferSubData(GL_UNIFORM_BUFFER, 4 * sizeof(glm::mat4)+ sizeof(glm::vec4), sizeof(glm::vec2), glm::value_ptr(noiseScale));//never changes
glBindBuffer(GL_UNIFORM_BUFFER, 0);

calculateFrustumPlanes(cameraMatrix, perspectiveProjectionMatrix, frustumPlanes);
Expand Down
14 changes: 12 additions & 2 deletions src/GLHelper.h
Expand Up @@ -197,15 +197,21 @@ class GLHelper {
GLuint depthOnlyFrameBufferPoint;
GLuint depthCubemapPoint;

GLuint depthOnlyFrameBufferSSAO;
GLuint depthMapSSAO;

unsigned int noiseTexture;

Options *options;

const uint_fast32_t lightUniformSize = (sizeof(glm::mat4) * 7) + (2 * sizeof(glm::vec4));
const uint32_t playerUniformSize = 3 * sizeof(glm::mat4) + sizeof(glm::vec4);
const uint32_t playerUniformSize = 4 * sizeof(glm::mat4) + sizeof(glm::vec4) + sizeof(glm::vec4);
int32_t materialUniformSize = 2 * sizeof(glm::vec3) + sizeof(float) + sizeof(GLuint);
int32_t modelUniformSize = sizeof(glm::mat4);

glm::mat4 cameraMatrix;
glm::mat4 perspectiveProjectionMatrix;
glm::mat4 inverseTransposeProjection;
std::vector<glm::vec4>frustumPlanes;
glm::mat4 orthogonalProjectionMatrix;
glm::mat4 lightProjectionMatrixDirectional;
Expand Down Expand Up @@ -234,7 +240,7 @@ class GLHelper {
#ifndef NDEBUG
GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (fbStatus != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "FB status is " << fbStatus << std::endl;
std::cerr << "FB status while " << callerFunc << " is " << fbStatus << std::endl;
}
bool hasError = false;
while ((error = glGetError()) != GL_NO_ERROR) {
Expand Down Expand Up @@ -311,6 +317,8 @@ class GLHelper {
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFrameBufferDirectional);
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, depthOnlyFrameBufferSSAO);
glClear(GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

renderTriangleCount = 0;
Expand Down Expand Up @@ -382,6 +390,8 @@ class GLHelper {

void switchRenderToShadowMapPoint();

void switchRenderToSSAO();

void switchRenderToDefault();

int getMaxTextureImageUnits() const {
Expand Down

0 comments on commit adc4756

Please sign in to comment.