From ae516a8007a6f5701034d1792718e3cf9c494459 Mon Sep 17 00:00:00 2001 From: Nigel Barink Date: Fri, 2 Jun 2023 20:07:32 +0200 Subject: [PATCH] Irradiance Map --- Shaders/irradienceconv.fs | 35 +++++++++++++++++++++++++++ Shaders/pbr.fs | 17 +++++++++---- Shaders/skybox2.vs | 13 ++++++++++ src/Renderer/Renderer.cpp | 50 +++++++++++++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 Shaders/irradienceconv.fs create mode 100644 Shaders/skybox2.vs diff --git a/Shaders/irradienceconv.fs b/Shaders/irradienceconv.fs new file mode 100644 index 0000000..bc981d7 --- /dev/null +++ b/Shaders/irradienceconv.fs @@ -0,0 +1,35 @@ +#version 460 core +out vec4 FragColor; +in vec3 localPos; + +uniform samplerCube environmentMap; + +const float PI = 3.14159265359; + +void main(){ + vec3 normal = normalize(localPos); + + vec3 irradiance = vec3(0.0); + + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, normal)); + up = normalize(cross(normal, right)); + + float sampleDelta = 0.025; + float nrSamples = 0.0; + + for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta){ + for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta){ + // spherical to cartesian + vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); + // tangent space to world + vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * normal; + + + irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta); + nrSamples++; + } + } + irradiance = PI * irradiance * (1.0 / float(nrSamples)); + FragColor = vec4(irradiance,1.0); +} \ No newline at end of file diff --git a/Shaders/pbr.fs b/Shaders/pbr.fs index 6e69a49..254393b 100644 --- a/Shaders/pbr.fs +++ b/Shaders/pbr.fs @@ -12,6 +12,8 @@ uniform sampler2D metallicMap; uniform sampler2D normalMap; uniform sampler2D roughnessMap; uniform sampler2D aoMap; +uniform samplerCube irradianceMap; + uniform vec3 lightPositions[4]; uniform vec3 lightColors[4]; @@ -21,9 +23,9 @@ const float PI = 3.14159265359; // ratio Refraction vs Reflection (F function) -vec3 fresnelSchlick (float cosTheta, vec3 F0) +vec3 fresnelSchlick (float cosTheta, vec3 F0, float roughness) { - return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); + return F0 + (max(vec3(1.0- roughness), F0)- F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); } // Calculate Normal distribution (D function) @@ -102,7 +104,7 @@ void main(){ float NDF = DistributionGGX(N,H, roughness); float G = GeometrySmith(N,V,L, roughness); - vec3 F = fresnelSchlick(max(dot(H,V), 0.0), F0); + vec3 F = fresnelSchlick(max(dot(H,V), 0.0), F0, roughness); vec3 kS = F; vec3 kD = vec3(1.0) - kS; @@ -118,8 +120,15 @@ void main(){ Lo += (kD * albedo / PI + specular) * radiance * NdotL; } + + // Calculate the ambient term and add it - vec3 ambient = vec3(0.03) * albedo * ao; + vec3 kS = fresnelSchlick(max(dot(N,V), 0.0), F0, roughness); + vec3 kD = 1.0 - kS; + kD *= 1.0 - metallic; + vec3 irradiance = texture(irradianceMap, N).rgb; + vec3 diffuse = irradiance* albedo; + vec3 ambient = (kD * diffuse) * ao; vec3 color = ambient + Lo; // HDR tonemapping diff --git a/Shaders/skybox2.vs b/Shaders/skybox2.vs new file mode 100644 index 0000000..9361306 --- /dev/null +++ b/Shaders/skybox2.vs @@ -0,0 +1,13 @@ +#version 460 core +layout (location = 0) in vec3 aPos; + +out vec3 localPos; + +uniform mat4 projection; +uniform mat4 view; + +void main() +{ + localPos = aPos; + gl_Position = projection * view * vec4(localPos ,1.0); +} \ No newline at end of file diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp index 5a16f11..8ba5ff6 100644 --- a/src/Renderer/Renderer.cpp +++ b/src/Renderer/Renderer.cpp @@ -120,7 +120,7 @@ void renderCube() { } - +unsigned int irradianceMap; unsigned int envCubemap; unsigned int envMapVAO; void Renderer::Setup() @@ -219,7 +219,46 @@ void Renderer::Setup() renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Generate irradiancemap + glGenTextures(1, &irradianceMap); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); + for (unsigned int i = 0; i < 6; ++i) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, nullptr); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); + + + auto irradianceShader = Shader(); + irradianceShader.Load("../Shaders/skybox2.vs", "../Shaders/irradienceconv.fs"); + irradianceShader.use(); + irradianceShader.setInt("environmentMap", 0); + irradianceShader.setMat4("projection", captureProjection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); + + glViewport(0, 0, 32, 32); + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + for (unsigned int i = 0; i < 6; ++i) { + irradianceShader.setMat4("view", captureViews[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + renderCube(); + } glViewport(0, 0, 800, 600); // restore viewport; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + + std::vector m_skyboxVertices = { // positions @@ -325,8 +364,6 @@ void Renderer::resize(int width, int height ) { } - - unsigned int sphereVAO = 0; unsigned int indexCount; void renderSphere() { @@ -419,7 +456,6 @@ void renderSphere() { glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0); } - void Renderer::Render(Scene& scene) { @@ -503,6 +539,7 @@ void Renderer::Render(Scene& scene) shader.setInt("metallicMap", 2); shader.setInt("roughnessMap", 3); shader.setInt("aoMap", 4); + shader.setInt("irradianceMap", 5); shader.setMat4("projection", projection); view = scene.MainCamera.GetViewMatrix(); @@ -521,10 +558,13 @@ void Renderer::Render(Scene& scene) glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, roughness); - glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, ao); + glActiveTexture(GL_TEXTURE5); + glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); + + // Render Spheres model = glm::mat4(1.0f); for (int row = 0; row < nrRows; ++row) {