SSAO getting close (excited)

simple_math_single_header
Martin Felis 2018-04-05 12:39:30 +02:00
parent 532a0fa9f2
commit 39d2bb68f8
9 changed files with 205 additions and 14 deletions

View File

@ -1,6 +1,6 @@
#version 150 core #version 150 core
in vec2 ioUV; in vec2 ioFragTexCoords;
out vec3 outColor; out vec3 outColor;
@ -10,7 +10,7 @@ uniform float uNear;
uniform float uFar; uniform float uFar;
void main() { void main() {
float z = texture(uDepthTexture, ioUV).r; float z = texture(uDepthTexture, ioFragTexCoords).r;
float c; float c;
if (uIsOrthographic == 1.0) { if (uIsOrthographic == 1.0) {
c = z; c = z;

View File

@ -1,11 +1,11 @@
#version 150 core #version 150 core
in vec2 ioUV; in vec2 ioFragTexCoords;
out vec4 outColor; out vec4 outColor;
uniform sampler2D uTexture; uniform sampler2D uTexture;
void main() { void main() {
outColor = texture(uTexture, ioUV); outColor = texture(uTexture, ioFragTexCoords);
} }

45
data/shaders/fs_ssao.glsl Normal file
View File

@ -0,0 +1,45 @@
#version 150 core
in vec2 ioFragTexCoords;
out vec3 outColor;
uniform sampler2D uPositions;
uniform sampler2D uNormals;
uniform sampler2D uNoise;
uniform float uRadius;
uniform float uBias;
uniform int uSampleCount;
uniform vec3 uSamples[64];
uniform mat4 uProjection;
void main() {
vec2 noise_scale = textureSize(uPositions, 0) / 2.0;
vec3 position = texture(uPositions, ioFragTexCoords).xyz;
vec3 normal = normalize(texture(uNormals, ioFragTexCoords)).rgb;
vec3 random_vector = normalize(texture(uNoise, ioFragTexCoords * noise_scale).xyz);
vec3 tangent = normalize(random_vector - normal * dot(random_vector, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3 (tangent, bitangent, normal);
float occlusion = 0.0;
for (int i = 0; i < uSampleCount; ++i) {
vec3 sample = TBN * uSamples[i];
sample = position + sample * uRadius;
vec4 offset = vec4(sample, 1.0);
offset = uProjection * offset;
offset.xyz /= offset.w;
offset.xyz = offset.xyz * 0.5 + 0.5;
float sample_depth = texture(uPositions, offset.xy).z;
float range_check = smoothstep(0.0, 1.0, uRadius / abs(position.z - sample_depth));
occlusion += (sample_depth >= sample.z + uBias ? 1.0 : 0.0) * range_check;
}
occlusion = 1.0 - (occlusion / uSampleCount);
outColor = vec3(occlusion);
}

View File

@ -1,5 +1,4 @@
#version 150 core #version 150 core
#extension GL_ARB_explicit_attrib_location : require
in vec4 inCoord; in vec4 inCoord;
in vec3 inNormal; in vec3 inNormal;
@ -21,11 +20,11 @@ smooth out vec4 ioFragColor;
out vec4 ioFragPosLightSpace; out vec4 ioFragPosLightSpace;
void main() { void main() {
ioFragPosition = (uModelMatrix * inCoord).xyz; ioFragPosition = (uViewMatrix * uModelMatrix * inCoord).xyz;
ioFragNormal = transpose(inverse(mat3(uModelMatrix))) * inNormal; ioFragNormal = transpose(inverse(mat3(uModelMatrix))) * inNormal;
ioFragTexCoords = inUV; ioFragTexCoords = inUV;
ioFragColor = inColor; ioFragColor = inColor;
ioFragPosLightSpace = uLightSpaceMatrix * vec4(ioFragPosition, 1.0); ioFragPosLightSpace = uLightSpaceMatrix * uModelMatrix * inCoord;
gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * inCoord; gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * inCoord;
} }

View File

@ -3,9 +3,9 @@
in vec4 inCoord; in vec4 inCoord;
in vec2 inUV; in vec2 inUV;
out vec2 ioUV; out vec2 ioFragTexCoords;
void main() { void main() {
ioUV = inUV; ioFragTexCoords = inUV;
gl_Position = inCoord; gl_Position = inCoord;
} }

View File

@ -78,5 +78,8 @@ inline void gLog (const char* format, ...) {
fprintf(gLogFile, "%s\n", buffer); fprintf(gLogFile, "%s\n", buffer);
fflush(gLogFile); fflush(gLogFile);
}
inline float gRandomFloat() {
return (static_cast<float>(rand()) / static_cast<float>(RAND_MAX));
} }

View File

@ -17,6 +17,7 @@ float moving_factor = 1.0f;
struct RendererSettings { struct RendererSettings {
bool DrawDepth = false; bool DrawDepth = false;
bool DrawLightDepth = false; bool DrawLightDepth = false;
bool DrawSSAO = false;
}; };
static RendererSettings sRendererSettings; static RendererSettings sRendererSettings;
@ -87,8 +88,9 @@ static void module_serialize (
Serializer* serializer) { Serializer* serializer) {
SerializeBool(*serializer, "protot.RenderModule.DrawDepth", sRendererSettings.DrawDepth); SerializeBool(*serializer, "protot.RenderModule.DrawDepth", sRendererSettings.DrawDepth);
SerializeBool(*serializer, "protot.RenderModule.DrawLightDepth", sRendererSettings.DrawLightDepth); SerializeBool(*serializer, "protot.RenderModule.DrawLightDepth", sRendererSettings.DrawLightDepth);
SerializeBool(*serializer, "protot.RenderModule.mIsSSAOEnabled", gRenderer->mIsSSAOEnabled); SerializeBool(*serializer, "protot.RenderModule.DrawSSAO", sRendererSettings.DrawSSAO);
SerializeBool(*serializer, "protot.RenderModule.mIsSSAOEnabled", gRenderer->mIsSSAOEnabled);
SerializeBool(*serializer, "protot.RenderModule.Camera.mIsOrthographic", gRenderer->mCamera.mIsOrthographic); SerializeBool(*serializer, "protot.RenderModule.Camera.mIsOrthographic", gRenderer->mCamera.mIsOrthographic);
SerializeFloat(*serializer, "protot.RenderModule.Camera.mFov", gRenderer->mCamera.mFov); SerializeFloat(*serializer, "protot.RenderModule.Camera.mFov", gRenderer->mCamera.mFov);
SerializeVec3(*serializer, "protot.RenderModule.Camera.mEye", gRenderer->mCamera.mEye); SerializeVec3(*serializer, "protot.RenderModule.Camera.mEye", gRenderer->mCamera.mEye);
@ -163,8 +165,6 @@ const struct module_api MODULE_API = {
}; };
} }
void Light::Initialize() { void Light::Initialize() {
gLog("Initializing light"); gLog("Initializing light");
mShadowMapProgram = RenderProgram("data/shaders/vs_shadowmap.vert", "data/shaders/fs_shadowmap.frag"); mShadowMapProgram = RenderProgram("data/shaders/vs_shadowmap.vert", "data/shaders/fs_shadowmap.frag");
@ -374,6 +374,14 @@ void Renderer::Initialize(int width, int height) {
mRenderQuadProgramDepth.RegisterFileModification(); mRenderQuadProgramDepth.RegisterFileModification();
assert(load_result); assert(load_result);
// Program for SSAO
mSSAOProgram = RenderProgram("data/shaders/vs_passthrough.glsl", "data/shaders/fs_ssao.glsl");
load_result = mSSAOProgram.Load();
mSSAOProgram.RegisterFileModification();
assert(load_result);
InitializeSSAOKernelAndNoise();
// Render Target // Render Target
gLog("Initializing main render target size: %d,%d", width, height); gLog("Initializing main render target size: %d,%d", width, height);
int render_target_flags = RenderTarget::EnableColor int render_target_flags = RenderTarget::EnableColor
@ -392,6 +400,9 @@ void Renderer::Initialize(int width, int height) {
mRenderTarget.mLinearizeDepthProgram = mRenderQuadProgramDepth; mRenderTarget.mLinearizeDepthProgram = mRenderQuadProgramDepth;
mRenderTarget.mLinearizeDepthProgram.RegisterFileModification(); mRenderTarget.mLinearizeDepthProgram.RegisterFileModification();
// SSAO Target
mSSAOTarget.Initialize(width, height, RenderTarget::EnableColor);
// Light // Light
mLight.Initialize(); mLight.Initialize();
mLight.mShadowMapTarget.mVertexArray = &gVertexArray; mLight.mShadowMapTarget.mVertexArray = &gVertexArray;
@ -406,6 +417,9 @@ void Renderer::Initialize(int width, int height) {
} }
void Renderer::Shutdown() { void Renderer::Shutdown() {
if (mSSAONoiseTexture != -1) {
glDeleteTextures(1, &mSSAONoiseTexture);
}
} }
@ -428,6 +442,9 @@ void Renderer::RenderGl() {
|| mSceneAreaHeight != mRenderTarget.mHeight || mSceneAreaHeight != mRenderTarget.mHeight
|| mRenderTarget.mFlags != required_render_flags ) { || mRenderTarget.mFlags != required_render_flags ) {
mRenderTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, required_render_flags); mRenderTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, required_render_flags);
if (mIsSSAOEnabled) {
mSSAOTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, RenderTarget::EnableColor);
}
} }
if (mCamera.mWidth != mSceneAreaWidth if (mCamera.mWidth != mSceneAreaWidth
@ -522,6 +539,46 @@ void Renderer::RenderGl() {
if (mSettings->DrawDepth) { if (mSettings->DrawDepth) {
mRenderTarget.RenderToLinearizedDepth(mCamera.mNear, mCamera.mFar, mCamera.mIsOrthographic); mRenderTarget.RenderToLinearizedDepth(mCamera.mNear, mCamera.mFar, mCamera.mIsOrthographic);
} }
if (mIsSSAOEnabled) {
mSSAOTarget.Bind();
glViewport(0, 0, mCamera.mWidth, mCamera.mHeight);
GLenum draw_attachment_0[] = {GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_attachment_0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
// Positions
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mRenderTarget.mPositionTexture);
// Normals
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mRenderTarget.mNormalTexture);
// TODO: noise texture
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, mSSAONoiseTexture);
glUseProgram(mSSAOProgram.mProgramId);
mSSAOProgram.SetInt("uPositions", 0);
mSSAOProgram.SetInt("uNormals", 1);
mSSAOProgram.SetInt("uNoise", 2);
mSSAOProgram.SetFloat("uRadius", mSSAORadius);
mSSAOProgram.SetFloat("uBias", mSSAOBias);
mSSAOProgram.SetInt("uSampleCount", mSSAOKernel.size());
mSSAOProgram.SetMat44("uProjection", mCamera.mProjectionMatrix);
mSSAOProgram.SetVec3Array("uSamples", mSSAOKernel.size(), &mSSAOKernel[0][0]);
// for (int i = 0; i < mSSAOKernel.size(); ++i) {
// mSSAOProgram.SetVec3(std::string("uSamples[" + std::to_string(i) + "]").c_str(), mSSAOKernel[i]);
// }
gVertexArray.Bind();
gScreenQuad.Draw(GL_TRIANGLES);
}
} }
void Renderer::RenderScene(RenderProgram &program, const Camera& camera) { void Renderer::RenderScene(RenderProgram &program, const Camera& camera) {
@ -593,10 +650,33 @@ void Renderer::RenderScene(RenderProgram &program, const Camera& camera) {
void Renderer::DrawGui() { void Renderer::DrawGui() {
if (ImGui::BeginDock("Scene")) { if (ImGui::BeginDock("Scene")) {
ImGui::Checkbox("Draw Depth", &mSettings->DrawDepth); static int e = 0;
if (mSettings->DrawDepth) {
e = 1;
} else if (mSettings->DrawSSAO) {
e = 2;
}
ImGui::RadioButton("Default", &e, 0); ImGui::SameLine();
ImGui::RadioButton("Depth", &e, 1); ImGui::SameLine();
ImGui::RadioButton("SSAO", &e, 2);
switch (e) {
case 0: mSettings->DrawDepth = 0;
mSettings->DrawSSAO = 0;
break;
case 1: mSettings->DrawDepth = 1;
mSettings->DrawSSAO = 0;
break;
case 2: mSettings->DrawDepth = 0;
mSettings->DrawSSAO = 1;
break;
}
if (mSettings->DrawDepth) { if (mSettings->DrawDepth) {
mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mLinearizedDepthTexture; mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mLinearizedDepthTexture;
} else if (mSettings->DrawSSAO) {
mRenderTextureRef.mTextureIdPtr = &mSSAOTarget.mColorTexture;
} else { } else {
mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mColorTexture; mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mColorTexture;
} }
@ -628,6 +708,14 @@ void Renderer::DrawGui() {
ImGui::Checkbox("Enable SSAO", &mIsSSAOEnabled); ImGui::Checkbox("Enable SSAO", &mIsSSAOEnabled);
if (mIsSSAOEnabled) { if (mIsSSAOEnabled) {
ImGui::SliderFloat("Radius", &mSSAORadius, 0.0f, 1.0f);
ImGui::SliderFloat("Bias", &mSSAOBias, 0.0f, 0.1f);
ImGui::SliderInt("Samples", &mSSAOKernelSize, 1, 64);
if (mSSAOKernelSize != mSSAOKernel.size()) {
InitializeSSAOKernelAndNoise();
}
ImGui::Text("Position Texture"); ImGui::Text("Position Texture");
mPositionTextureRef.mTextureIdPtr = &mRenderTarget.mPositionTexture; mPositionTextureRef.mTextureIdPtr = &mRenderTarget.mPositionTexture;
mPositionTextureRef.magic = (GLuint)0xbadface; mPositionTextureRef.magic = (GLuint)0xbadface;
@ -657,3 +745,43 @@ void Renderer::DrawGui() {
ImGui::EndDock(); ImGui::EndDock();
} }
void Renderer::InitializeSSAOKernelAndNoise() {
mSSAOKernel.clear();
for (unsigned int i = 0; i < mSSAOKernelSize; ++i) {
Vector3f sample(
gRandomFloat() * 2.0f - 1.0f,
gRandomFloat() * 2.0f - 1.0f,
gRandomFloat()
);
sample.normalize();
// Have a higher distribution of samples close to the origin
float scale = (float) i / mSSAOKernelSize;
scale = 0.1 + scale * scale * (1.0f - 0.1);
mSSAOKernel.push_back(sample * scale);
}
std::vector<Vector3f> noise_vectors;
for (unsigned int i = 0; i < 16; ++i) {
Vector3f noise(
gRandomFloat() * 2.0f - 1.0f,
gRandomFloat() * 2.0f - 1.0f,
0.0f);
noise_vectors.push_back(noise);
}
if (mSSAONoiseTexture != -1) {
glDeleteTextures(1, &mSSAONoiseTexture);
}
glGenTextures(1, &mSSAONoiseTexture);
glBindTexture(GL_TEXTURE_2D, mSSAONoiseTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, 4, 4, 0, GL_RGB, GL_FLOAT, &noise_vectors[0][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);
}

View File

@ -71,12 +71,21 @@ struct Renderer {
RenderProgram mDefaultProgram; RenderProgram mDefaultProgram;
RenderProgram mRenderQuadProgramColor; RenderProgram mRenderQuadProgramColor;
RenderProgram mRenderQuadProgramDepth; RenderProgram mRenderQuadProgramDepth;
RenderProgram mSSAOProgram;
RenderTarget mRenderTarget; RenderTarget mRenderTarget;
RenderTarget mSSAOTarget;
GLTextureRef mRenderTextureRef = { (int)0xbadface }; GLTextureRef mRenderTextureRef = { (int)0xbadface };
GLTextureRef mPositionTextureRef = { (int)0xbadface }; GLTextureRef mPositionTextureRef = { (int)0xbadface };
GLTextureRef mNormalTextureRef = { (int)0xbadface }; GLTextureRef mNormalTextureRef = { (int)0xbadface };
float mSSAORadius = 0.5f;
float mSSAOBias = 0.025f;
int mSSAOKernelSize = 64;
std::vector<Vector3f> mSSAOKernel;
GLuint mSSAONoiseTexture = -1;
Renderer() : Renderer() :
mInitialized(false), mInitialized(false),
mWidth (0), mWidth (0),
@ -88,4 +97,6 @@ struct Renderer {
void RenderGl(); void RenderGl();
void RenderScene(RenderProgram &program, const Camera& camera); void RenderScene(RenderProgram &program, const Camera& camera);
void DrawGui(); void DrawGui();
void InitializeSSAOKernelAndNoise();
}; };

View File

@ -218,6 +218,11 @@ struct RenderProgram : AFileModificationListener {
glUniform3fv(location, 1, vec.data()); glUniform3fv(location, 1, vec.data());
return location; return location;
} }
GLint SetVec3Array(const char* name, int count, const float* array) {
GLint location = glGetUniformLocation(mProgramId, name);
glUniform3fv(location, count, array);
return location;
}
GLint SetVec4(const char* name, const Vector3f& vec, float w = 1.0f) { GLint SetVec4(const char* name, const Vector3f& vec, float w = 1.0f) {
GLint location = glGetUniformLocation(mProgramId, name); GLint location = glGetUniformLocation(mProgramId, name);
glUniform4f(location, vec[0], vec[1], vec[2], w); glUniform4f(location, vec[0], vec[1], vec[2], w);