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
in vec2 ioUV;
in vec2 ioFragTexCoords;
out vec3 outColor;
@ -10,7 +10,7 @@ uniform float uNear;
uniform float uFar;
void main() {
float z = texture(uDepthTexture, ioUV).r;
float z = texture(uDepthTexture, ioFragTexCoords).r;
float c;
if (uIsOrthographic == 1.0) {
c = z;

View File

@ -1,11 +1,11 @@
#version 150 core
in vec2 ioUV;
in vec2 ioFragTexCoords;
out vec4 outColor;
uniform sampler2D uTexture;
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
#extension GL_ARB_explicit_attrib_location : require
in vec4 inCoord;
in vec3 inNormal;
@ -21,11 +20,11 @@ smooth out vec4 ioFragColor;
out vec4 ioFragPosLightSpace;
void main() {
ioFragPosition = (uModelMatrix * inCoord).xyz;
ioFragPosition = (uViewMatrix * uModelMatrix * inCoord).xyz;
ioFragNormal = transpose(inverse(mat3(uModelMatrix))) * inNormal;
ioFragTexCoords = inUV;
ioFragColor = inColor;
ioFragPosLightSpace = uLightSpaceMatrix * vec4(ioFragPosition, 1.0);
ioFragPosLightSpace = uLightSpaceMatrix * uModelMatrix * inCoord;
gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * inCoord;
}

View File

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

View File

@ -78,5 +78,8 @@ inline void gLog (const char* format, ...) {
fprintf(gLogFile, "%s\n", buffer);
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 {
bool DrawDepth = false;
bool DrawLightDepth = false;
bool DrawSSAO = false;
};
static RendererSettings sRendererSettings;
@ -87,8 +88,9 @@ static void module_serialize (
Serializer* serializer) {
SerializeBool(*serializer, "protot.RenderModule.DrawDepth", sRendererSettings.DrawDepth);
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);
SerializeFloat(*serializer, "protot.RenderModule.Camera.mFov", gRenderer->mCamera.mFov);
SerializeVec3(*serializer, "protot.RenderModule.Camera.mEye", gRenderer->mCamera.mEye);
@ -163,8 +165,6 @@ const struct module_api MODULE_API = {
};
}
void Light::Initialize() {
gLog("Initializing light");
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();
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
gLog("Initializing main render target size: %d,%d", width, height);
int render_target_flags = RenderTarget::EnableColor
@ -392,6 +400,9 @@ void Renderer::Initialize(int width, int height) {
mRenderTarget.mLinearizeDepthProgram = mRenderQuadProgramDepth;
mRenderTarget.mLinearizeDepthProgram.RegisterFileModification();
// SSAO Target
mSSAOTarget.Initialize(width, height, RenderTarget::EnableColor);
// Light
mLight.Initialize();
mLight.mShadowMapTarget.mVertexArray = &gVertexArray;
@ -406,6 +417,9 @@ void Renderer::Initialize(int width, int height) {
}
void Renderer::Shutdown() {
if (mSSAONoiseTexture != -1) {
glDeleteTextures(1, &mSSAONoiseTexture);
}
}
@ -428,6 +442,9 @@ void Renderer::RenderGl() {
|| mSceneAreaHeight != mRenderTarget.mHeight
|| mRenderTarget.mFlags != required_render_flags ) {
mRenderTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, required_render_flags);
if (mIsSSAOEnabled) {
mSSAOTarget.Resize(mSceneAreaWidth, mSceneAreaHeight, RenderTarget::EnableColor);
}
}
if (mCamera.mWidth != mSceneAreaWidth
@ -522,6 +539,46 @@ void Renderer::RenderGl() {
if (mSettings->DrawDepth) {
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) {
@ -593,10 +650,33 @@ void Renderer::RenderScene(RenderProgram &program, const Camera& camera) {
void Renderer::DrawGui() {
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) {
mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mLinearizedDepthTexture;
} else if (mSettings->DrawSSAO) {
mRenderTextureRef.mTextureIdPtr = &mSSAOTarget.mColorTexture;
} else {
mRenderTextureRef.mTextureIdPtr = &mRenderTarget.mColorTexture;
}
@ -628,6 +708,14 @@ void Renderer::DrawGui() {
ImGui::Checkbox("Enable SSAO", &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");
mPositionTextureRef.mTextureIdPtr = &mRenderTarget.mPositionTexture;
mPositionTextureRef.magic = (GLuint)0xbadface;
@ -657,3 +745,43 @@ void Renderer::DrawGui() {
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 mRenderQuadProgramColor;
RenderProgram mRenderQuadProgramDepth;
RenderProgram mSSAOProgram;
RenderTarget mRenderTarget;
RenderTarget mSSAOTarget;
GLTextureRef mRenderTextureRef = { (int)0xbadface };
GLTextureRef mPositionTextureRef = { (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() :
mInitialized(false),
mWidth (0),
@ -88,4 +97,6 @@ struct Renderer {
void RenderGl();
void RenderScene(RenderProgram &program, const Camera& camera);
void DrawGui();
void InitializeSSAOKernelAndNoise();
};

View File

@ -218,6 +218,11 @@ struct RenderProgram : AFileModificationListener {
glUniform3fv(location, 1, vec.data());
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 location = glGetUniformLocation(mProgramId, name);
glUniform4f(location, vec[0], vec[1], vec[2], w);