From e4587f7c82a23ba874e7a9390e266592336c460b Mon Sep 17 00:00:00 2001 From: Nigel Barink Date: Mon, 5 Jun 2023 18:40:06 +0200 Subject: [PATCH] Specular BDRF --- PBRWithSpecular.png | 3 + Shaders/BRDFIntegration.fs | 111 +++++++++++++++ Shaders/BRDFIntegration.vs | 10 ++ Shaders/HDRSkybox.fs | 1 - Shaders/pbr.fs | 21 ++- Shaders/prefilter.fs | 71 ++++++++++ Textures/Iron-Scuffed/albedo.png | 3 + Textures/Iron-Scuffed/ao.png | 3 + Textures/Iron-Scuffed/metallic.png | 3 + Textures/Iron-Scuffed/normal.png | 3 + Textures/Iron-Scuffed/roughness.png | 3 + Textures/beaten-down-brick/albedo.png | 3 + Textures/beaten-down-brick/ao.png | 3 + .../beaten-down-brick_height.png | 3 + Textures/beaten-down-brick/metallic.png | 3 + Textures/beaten-down-brick/normal.png | 3 + Textures/beaten-down-brick/roughness.png | 3 + Textures/night_2k.hdr | 3 + Textures/space-cruiser/albedo.png | 3 + Textures/space-cruiser/ao.png | 3 + Textures/space-cruiser/metallic.png | 3 + Textures/space-cruiser/normal.png | 3 + Textures/space-cruiser/roughness.png | 3 + .../space-cruiser-panels2_height.png | 3 + src/Renderer/Renderer.cpp | 131 ++++++++++++++++-- 25 files changed, 383 insertions(+), 19 deletions(-) create mode 100644 PBRWithSpecular.png create mode 100644 Shaders/BRDFIntegration.fs create mode 100644 Shaders/BRDFIntegration.vs create mode 100644 Shaders/prefilter.fs create mode 100644 Textures/Iron-Scuffed/albedo.png create mode 100644 Textures/Iron-Scuffed/ao.png create mode 100644 Textures/Iron-Scuffed/metallic.png create mode 100644 Textures/Iron-Scuffed/normal.png create mode 100644 Textures/Iron-Scuffed/roughness.png create mode 100644 Textures/beaten-down-brick/albedo.png create mode 100644 Textures/beaten-down-brick/ao.png create mode 100644 Textures/beaten-down-brick/beaten-down-brick_height.png create mode 100644 Textures/beaten-down-brick/metallic.png create mode 100644 Textures/beaten-down-brick/normal.png create mode 100644 Textures/beaten-down-brick/roughness.png create mode 100644 Textures/night_2k.hdr create mode 100644 Textures/space-cruiser/albedo.png create mode 100644 Textures/space-cruiser/ao.png create mode 100644 Textures/space-cruiser/metallic.png create mode 100644 Textures/space-cruiser/normal.png create mode 100644 Textures/space-cruiser/roughness.png create mode 100644 Textures/space-cruiser/space-cruiser-panels2_height.png diff --git a/PBRWithSpecular.png b/PBRWithSpecular.png new file mode 100644 index 0000000..0e53c98 --- /dev/null +++ b/PBRWithSpecular.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:270534bcbb4a3a28e20401b876e09c377d87d2e3eef46dc8b74776d70d0a0c1f +size 650871 diff --git a/Shaders/BRDFIntegration.fs b/Shaders/BRDFIntegration.fs new file mode 100644 index 0000000..644795f --- /dev/null +++ b/Shaders/BRDFIntegration.fs @@ -0,0 +1,111 @@ +#version 460 core +out vec2 FragColor; +in vec2 TexCoords; + + +const float PI = 3.14159265359; + + +// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html +// efficient VanDerCorpus calculation. +float RadicalInverse_VdC(uint bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N) +{ + return vec2(float(i)/float(N), RadicalInverse_VdC(i)); +} + +float GeometrySchlickGGX(float NdotV, float roughness) +{ + float a = roughness; + float k = (a * a) / 2.0; + + float nom = NdotV; + float denom = NdotV * (1.0 - k) + k; + + return nom / denom; +} + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){ + float a = roughness*roughness; + + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // Spherical to cartesian + vec3 H; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // tangent space to world sample vector + vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up,N)); + vec3 bitangent = cross(N, tangent); + vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; + + return normalize(sampleVec); +} + + +float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) +{ + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); + + return ggx1 * ggx2; +} + +vec2 IntegrateBRDF (float NdotV, float roughness){ + + vec3 V; + V.x = sqrt(1.0 - NdotV * NdotV); + V.y = 0.0; + V.z = NdotV; + + float A = 0.0; + float B = 0.0; + + vec3 N = vec3(0.0,0.0,1.0); + + const uint SAMPLE_COUNT = 1024u; + for(uint i = 0u; i < SAMPLE_COUNT; ++i){ + vec2 Xi = Hammersley(i, SAMPLE_COUNT); + vec3 H = ImportanceSampleGGX(Xi, N, roughness); + vec3 L = normalize(2.0 * dot(V, H) * H - V); + + float NdotL = max(L.z, 0.0); + float NdotH = max(H.z, 0.0); + float VdotH = max(dot(V, H), 0.0); + + if(NdotL > 0.0) + { + float G = GeometrySmith(N, V, L, roughness); + float G_Vis = (G * VdotH) / (NdotH * NdotV); + float Fc = pow(1.0 - VdotH, 5.0); + + A += (1.0 - Fc) * G_Vis; + B += Fc * G_Vis; + } + } + A /= float(SAMPLE_COUNT); + B /= float(SAMPLE_COUNT); + return vec2(A, B); +} + +void main() +{ + vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y); + FragColor = integratedBRDF; +} diff --git a/Shaders/BRDFIntegration.vs b/Shaders/BRDFIntegration.vs new file mode 100644 index 0000000..0bc4e1a --- /dev/null +++ b/Shaders/BRDFIntegration.vs @@ -0,0 +1,10 @@ +#version 460 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec2 aTexCoords; + +out vec2 TexCoords; + +void main(){ + TexCoords = aTexCoords; + gl_Position = vec4(aPos, 1.0); +} \ No newline at end of file diff --git a/Shaders/HDRSkybox.fs b/Shaders/HDRSkybox.fs index 12afac5..45c4886 100644 --- a/Shaders/HDRSkybox.fs +++ b/Shaders/HDRSkybox.fs @@ -7,7 +7,6 @@ uniform samplerCube environmentMap; void main(){ vec3 envColor = texture(environmentMap, localPos).rgb; - envColor = envColor /(envColor + vec3(1.0)); envColor = pow(envColor, vec3(1.0/2.2)); diff --git a/Shaders/pbr.fs b/Shaders/pbr.fs index 254393b..649b22f 100644 --- a/Shaders/pbr.fs +++ b/Shaders/pbr.fs @@ -12,9 +12,12 @@ uniform sampler2D metallicMap; uniform sampler2D normalMap; uniform sampler2D roughnessMap; uniform sampler2D aoMap; -uniform samplerCube irradianceMap; +uniform samplerCube irradianceMap; +uniform samplerCube prefilterMap; +uniform sampler2D brdfLUT; + uniform vec3 lightPositions[4]; uniform vec3 lightColors[4]; @@ -78,6 +81,8 @@ vec3 getNormalFromNormalMap(){ return normalize(TBN * tangentNormal); } + + void main(){ vec3 albedo = pow(texture(albedoMap, TexCoords).rgb, vec3(2.2)); @@ -88,7 +93,9 @@ void main(){ vec3 N = getNormalFromNormalMap(); vec3 V = normalize(camPos - WorldPos); - + vec3 R = reflect(-V, N); + + vec3 F0 = vec3(0.04); F0 = mix(F0, albedo, metallic); @@ -128,7 +135,15 @@ void main(){ kD *= 1.0 - metallic; vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance* albedo; - vec3 ambient = (kD * diffuse) * ao; + + const float MAX_REFLECTION_LOD = 4.0; + vec3 prefilterColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; + vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N,V), 0.0), roughness)).rg; + vec3 specular = prefilterColor * (kS * envBRDF.x + envBRDF.y); + + + + vec3 ambient = (kD * diffuse + specular) * ao; vec3 color = ambient + Lo; // HDR tonemapping diff --git a/Shaders/prefilter.fs b/Shaders/prefilter.fs new file mode 100644 index 0000000..ad228ce --- /dev/null +++ b/Shaders/prefilter.fs @@ -0,0 +1,71 @@ +#version 460 core +out vec4 FragColor; +in vec3 localPos; + +uniform samplerCube environmentMap; +uniform float roughness; + +const float PI = 3.14159265359; + +vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){ + float a = roughness*roughness; + + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta*cosTheta); + + // Spherical to cartesian + vec3 H; + H.x = cos(phi) * sinTheta; + H.y = sin(phi) * sinTheta; + H.z = cosTheta; + + // tangent space to world sample vector + vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up,N)); + vec3 bitangent = cross(N, tangent); + vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z; + + return normalize(sampleVec); +} + + +// Generate Van Der Corput sequence +float RadicalInverse_VdC(uint bits){ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 +} + +vec2 Hammersley(uint i, uint N){ + return vec2(float(i)/float(N), RadicalInverse_VdC(i)); +} + +void main(){ + vec3 N = normalize(localPos); + vec3 R = N; + vec3 V = R; + + const uint SAMPLE_COUNT = 1024u; + float totalWeight = 0.0; + vec3 prefilteredColor = vec3(0.0); + for(uint i = 0u; i < SAMPLE_COUNT; ++i) + { + vec2 Xi = Hammersley(i, SAMPLE_COUNT); + vec3 H = ImportanceSampleGGX(Xi, N, roughness); + vec3 L = normalize(2.0 * dot(V,H) * H - V ); + + float NdotL = max(dot(N, L), 0.0); + if(NdotL > 0.0){ + prefilteredColor += texture(environmentMap, L).rgb * NdotL; + totalWeight += NdotL; + } + } + + prefilteredColor = prefilteredColor / totalWeight; + + FragColor = vec4(prefilteredColor, 1.0); +} \ No newline at end of file diff --git a/Textures/Iron-Scuffed/albedo.png b/Textures/Iron-Scuffed/albedo.png new file mode 100644 index 0000000..e731499 --- /dev/null +++ b/Textures/Iron-Scuffed/albedo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d10d3f3667099909184086588c6bf92b26fae83d6eb70e689f37941cf5ef0177 +size 19629 diff --git a/Textures/Iron-Scuffed/ao.png b/Textures/Iron-Scuffed/ao.png new file mode 100644 index 0000000..8d28e72 --- /dev/null +++ b/Textures/Iron-Scuffed/ao.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:239842079db09bd951d2c79c779a2b1b89ebf7212dfbb637519afb6d0dddde98 +size 13026 diff --git a/Textures/Iron-Scuffed/metallic.png b/Textures/Iron-Scuffed/metallic.png new file mode 100644 index 0000000..3fcaecd --- /dev/null +++ b/Textures/Iron-Scuffed/metallic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a532bf8dfc6ca8e6c486f81708121ea693b3d8729e50e70c8b6664de13bec60 +size 7859 diff --git a/Textures/Iron-Scuffed/normal.png b/Textures/Iron-Scuffed/normal.png new file mode 100644 index 0000000..c3c74ba --- /dev/null +++ b/Textures/Iron-Scuffed/normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:471139bc8d36dbb62cdbd35c6c471046f5151783eb53e7ee8c05d4019e28c507 +size 27098 diff --git a/Textures/Iron-Scuffed/roughness.png b/Textures/Iron-Scuffed/roughness.png new file mode 100644 index 0000000..9a32835 --- /dev/null +++ b/Textures/Iron-Scuffed/roughness.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf425de69daa965b8cabfd8e4430b4b7bb58b949cadf32ff746226b158b6919f +size 1762692 diff --git a/Textures/beaten-down-brick/albedo.png b/Textures/beaten-down-brick/albedo.png new file mode 100644 index 0000000..4a1c848 --- /dev/null +++ b/Textures/beaten-down-brick/albedo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b5eb12c0c38ee7ea89a8f06168262793a252f7ba144b78cea687be90f4bb569 +size 5853266 diff --git a/Textures/beaten-down-brick/ao.png b/Textures/beaten-down-brick/ao.png new file mode 100644 index 0000000..c636152 --- /dev/null +++ b/Textures/beaten-down-brick/ao.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ca8b8dc0a548b64e5475387adca12803fe7cfac8bf9c139be28b59dea5a3fe6 +size 1134309 diff --git a/Textures/beaten-down-brick/beaten-down-brick_height.png b/Textures/beaten-down-brick/beaten-down-brick_height.png new file mode 100644 index 0000000..6775229 --- /dev/null +++ b/Textures/beaten-down-brick/beaten-down-brick_height.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d4639cc085308d3b9cfb3c9cc72eed76dcd8c5bcaf73601ae7747c06fdde265 +size 1261444 diff --git a/Textures/beaten-down-brick/metallic.png b/Textures/beaten-down-brick/metallic.png new file mode 100644 index 0000000..57ee52c --- /dev/null +++ b/Textures/beaten-down-brick/metallic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:853c74cbddd9365725ee0f8e419931080c72fbb1f0be9eb70292e66327868198 +size 56038 diff --git a/Textures/beaten-down-brick/normal.png b/Textures/beaten-down-brick/normal.png new file mode 100644 index 0000000..21b6708 --- /dev/null +++ b/Textures/beaten-down-brick/normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:be5b02a5f348df55eaf580ceac7efc60e6269ac7c2ff857e9d9f74300f34c16e +size 8317624 diff --git a/Textures/beaten-down-brick/roughness.png b/Textures/beaten-down-brick/roughness.png new file mode 100644 index 0000000..65e3af6 --- /dev/null +++ b/Textures/beaten-down-brick/roughness.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eec12138ed9fc315a02a6638bb1b8547de0eec295996c849930b31ba97733a7a +size 4482702 diff --git a/Textures/night_2k.hdr b/Textures/night_2k.hdr new file mode 100644 index 0000000..8702035 --- /dev/null +++ b/Textures/night_2k.hdr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:35b5ef6d664b9d32db5ef852f52f97b4227a0dca1830e9c8bdb3af5dc2f169cf +size 7050455 diff --git a/Textures/space-cruiser/albedo.png b/Textures/space-cruiser/albedo.png new file mode 100644 index 0000000..83fb643 --- /dev/null +++ b/Textures/space-cruiser/albedo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec815efeb8281387ad70393c5923458a1cab95faa92bed8111e672cb588aad89 +size 4815677 diff --git a/Textures/space-cruiser/ao.png b/Textures/space-cruiser/ao.png new file mode 100644 index 0000000..00bf854 --- /dev/null +++ b/Textures/space-cruiser/ao.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aeeb0a82f268cf9aa3203aa3f5dddbb392527deb3644f0d1ccd49c671ef14e14 +size 1687125 diff --git a/Textures/space-cruiser/metallic.png b/Textures/space-cruiser/metallic.png new file mode 100644 index 0000000..b534e43 --- /dev/null +++ b/Textures/space-cruiser/metallic.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:786534d1a23636b96f1ad256073107d71f75a43bb19e0897c121dba53e0babe4 +size 85878 diff --git a/Textures/space-cruiser/normal.png b/Textures/space-cruiser/normal.png new file mode 100644 index 0000000..ad925c3 --- /dev/null +++ b/Textures/space-cruiser/normal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2d4bc47fb521824b193ac548b1dac7699bed4a9ce9cb530a2dd46169e2fd3e65 +size 4522050 diff --git a/Textures/space-cruiser/roughness.png b/Textures/space-cruiser/roughness.png new file mode 100644 index 0000000..3024411 --- /dev/null +++ b/Textures/space-cruiser/roughness.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:79ba1dc779726faa69aa74ed5a02bc90ea7a0fbce88ecb3c360316000d409c54 +size 3384003 diff --git a/Textures/space-cruiser/space-cruiser-panels2_height.png b/Textures/space-cruiser/space-cruiser-panels2_height.png new file mode 100644 index 0000000..387b90d --- /dev/null +++ b/Textures/space-cruiser/space-cruiser-panels2_height.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0909cd64df8bee6a50475af05a098c66e991f14be51eb7069350415d408e63e +size 209655 diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp index 8ba5ff6..5f59e45 100644 --- a/src/Renderer/Renderer.cpp +++ b/src/Renderer/Renderer.cpp @@ -119,12 +119,45 @@ void renderCube() { glBindVertexArray(0); } +unsigned int quadVAO = 0; +unsigned int quadVBO; +void renderQuad() +{ + if (quadVAO == 0) + { + float quadVertices[] = { + // positions // texture Coords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + // setup plane VAO + glGenVertexArrays(1, &quadVAO); + glGenBuffers(1, &quadVBO); + glBindVertexArray(quadVAO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); + } + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); +} + + +unsigned int brdfLUTTexture; +unsigned int prefilterMap; unsigned int irradianceMap; unsigned int envCubemap; unsigned int envMapVAO; void Renderer::Setup() { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Create ScreenVAO glGenVertexArrays(1, &ScreenVAO); glBindVertexArray(ScreenVAO); @@ -158,11 +191,11 @@ void Renderer::Setup() shaders[static_cast(RenderPass::PBR)].Load("../Shaders/pbr.vs", "../Shaders/pbr.fs"); - albedo = TextureFromFile("../Textures/rusted_iron/albedo.png", "."); - normal = TextureFromFile("../Textures/rusted_iron/normal.png", "."); - metallic = TextureFromFile("../Textures/rusted_iron/metallic.png", "."); - roughness = TextureFromFile("../Textures/rusted_iron/roughness.png", "."); - ao = TextureFromFile("../Textures/rusted_iron/ao.png","."); + albedo = TextureFromFile("../Textures/space-cruiser/albedo.png", "."); + normal = TextureFromFile("../Textures/space-cruiser/normal.png", "."); + metallic = TextureFromFile("../Textures/space-cruiser/metallic.png", "."); + roughness = TextureFromFile("../Textures/space-cruiser/roughness.png", "."); + ao = TextureFromFile("../Textures/space-cruiser/ao.png","."); // Create the skybox from an HDR equirectangular environment map @@ -199,7 +232,7 @@ void Renderer::Setup() auto eqShader = Shader(); eqShader.Load("../Shaders/HDRMap.vs", "../Shaders/HDRMap.fs"); - auto hdrTexture = LoadIBL("../Textures/photostudio.hdr"); + auto hdrTexture = LoadIBL("../Textures/night_2k.hdr"); eqShader.use(); eqShader.setInt("equirectangularMap", 0); @@ -319,6 +352,71 @@ void Renderer::Setup() glBindVertexArray(0); + glGenTextures(1, &prefilterMap); + glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); + for (unsigned int i = 0; i < 6; ++i) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 128, 128, 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_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + auto prefilterShader = Shader(); + prefilterShader.Load("../Shaders/skybox2.vs", "../Shaders/prefilter.fs"); + prefilterShader.setInt("environmentMap", 0); + prefilterShader.setMat4("projection", captureProjection); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); + + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + unsigned int maxMipLevels = 5; + for (unsigned int mip = 0; mip < maxMipLevels; ++mip) { + unsigned int mipWidth = 128 * std::pow(0.5, mip); + unsigned int mipHeight = 128 * std::pow(0.5, mip); + glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); + glViewport(0, 0, mipWidth, mipHeight); + + float roughness = (float)mip / (float)(maxMipLevels - 1); + prefilterShader.setFloat("roughness", roughness); + for (unsigned int i = 0; i < 6; ++i) { + prefilterShader.setMat4("view", captureViews[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + renderCube(); + } + } + + glGenTextures(1, &brdfLUTTexture); + + // Pre-allocate enough memory for the LUT texture + glBindTexture(GL_TEXTURE_2D, brdfLUTTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); + glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdfLUTTexture, 0); + + glViewport(0, 0, 512, 512); + auto brdfShader = Shader(); + brdfShader.Load("../Shaders/BRDFIntegration.vs", "../Shaders/BRDFIntegration.fs"); + + brdfShader.use(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + renderQuad(); + + glViewport(0, 0, 800, 600); // reset viewport + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } @@ -540,6 +638,9 @@ void Renderer::Render(Scene& scene) shader.setInt("roughnessMap", 3); shader.setInt("aoMap", 4); shader.setInt("irradianceMap", 5); + shader.setInt("prefilterMap", 6); + shader.setInt("brdfLUT", 7); + shader.setMat4("projection", projection); view = scene.MainCamera.GetViewMatrix(); @@ -564,6 +665,12 @@ void Renderer::Render(Scene& scene) glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); + glActiveTexture(GL_TEXTURE6); + glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); + + glActiveTexture(GL_TEXTURE7); + glBindTexture(GL_TEXTURE_2D, brdfLUTTexture); + // Render Spheres model = glm::mat4(1.0f); @@ -626,16 +733,10 @@ void Renderer::Render(Scene& scene) entity.Draw(OutlineShader); } - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glStencilMask(0xFF); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glStencilMask(0xFF); - */ - - - - - - + */ // 4. draw result to screen