diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
index d90027e..95a0438 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj
@@ -121,6 +121,7 @@
+
@@ -154,13 +155,16 @@
+
+
+
@@ -192,6 +196,7 @@
+
diff --git a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
index be9f632..ea62120 100644
--- a/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
+++ b/ArchitectureColoredPainting/ArchitectureColoredPainting.vcxproj.filters
@@ -210,6 +210,9 @@
Source Files
+
+ Source Files\Renderer
+
@@ -311,6 +314,15 @@
Resource Files\Shaders
+
+ Resource Files\Shaders
+
+
+ Resource Files\Shaders
+
+
+ Resource Files\Shaders
+
@@ -423,6 +435,9 @@
Header Files
+
+ Header Files\Renderer
+
diff --git a/ArchitectureColoredPainting/RendererWidget.ui b/ArchitectureColoredPainting/RendererWidget.ui
index c3a7631..e7ae4e5 100644
--- a/ArchitectureColoredPainting/RendererWidget.ui
+++ b/ArchitectureColoredPainting/RendererWidget.ui
@@ -115,11 +115,20 @@
-
-
+
+
+ 12
+
+
+ 12
+
+
+ 12
+
-
-
+
0
0
@@ -128,7 +137,7 @@
180
- Qt::Horizontal
+ Qt::Vertical
@@ -138,7 +147,23 @@
360
- Qt::Horizontal
+ Qt::Vertical
+
+
+
+ -
+
+
+ 1
+
+
+ 200
+
+
+ 1
+
+
+ Qt::Vertical
diff --git a/ArchitectureColoredPainting/res/MainWindow.qrc b/ArchitectureColoredPainting/res/MainWindow.qrc
index 83a1414..5fb0bed 100644
--- a/ArchitectureColoredPainting/res/MainWindow.qrc
+++ b/ArchitectureColoredPainting/res/MainWindow.qrc
@@ -28,6 +28,9 @@
Shaders/cubemap.vert
Shaders/skybox.frag
Shaders/skybox.vert
+ Shaders/irradiance_convolution.frag
+ Shaders/cubemap_prefilter.frag
+ Shaders/brdf_lut.comp
qt.conf
diff --git a/ArchitectureColoredPainting/res/Shaders/brdf_lut.comp b/ArchitectureColoredPainting/res/Shaders/brdf_lut.comp
new file mode 100644
index 0000000..651b12f
--- /dev/null
+++ b/ArchitectureColoredPainting/res/Shaders/brdf_lut.comp
@@ -0,0 +1,116 @@
+#version 450 core
+
+layout(local_size_x = 8, local_size_y = 8) in;
+layout(rg16f, binding = 0) uniform image2D brdfLUT;
+
+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));
+}
+// ----------------------------------------------------------------------------
+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);
+
+ // from spherical coordinates to cartesian coordinates - halfway vector
+ vec3 H;
+ H.x = cos(phi) * sinTheta;
+ H.y = sin(phi) * sinTheta;
+ H.z = cosTheta;
+
+ // from tangent-space H vector to world-space 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 GeometrySchlickGGX(float NdotV, float roughness)
+{
+ // note that we use a different k for IBL
+ float a = roughness;
+ float k = (a * a) / 2.0;
+
+ float nom = NdotV;
+ float denom = NdotV * (1.0 - k) + k;
+
+ return nom / denom;
+}
+// ----------------------------------------------------------------------------
+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)
+ {
+ // generates a sample vector that's biased towards the
+ // preferred alignment direction (importance sampling).
+ 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()
+{
+ uvec2 pixelLocation = gl_GlobalInvocationID.xy;
+ vec2 texCoords = vec2(pixelLocation)/vec2(imageSize(brdfLUT));
+ vec2 integratedBRDF = IntegrateBRDF(texCoords.x, texCoords.y);
+ imageStore(brdfLUT, ivec2(pixelLocation), vec4(integratedBRDF,0,0));
+}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/res/Shaders/cubemap_prefilter.frag b/ArchitectureColoredPainting/res/Shaders/cubemap_prefilter.frag
new file mode 100644
index 0000000..9214443
--- /dev/null
+++ b/ArchitectureColoredPainting/res/Shaders/cubemap_prefilter.frag
@@ -0,0 +1,107 @@
+#version 450 core
+out vec4 FragColor;
+in vec3 WorldPos;
+
+uniform samplerCube environmentMap;
+uniform float roughness;
+
+const float PI = 3.14159265359;
+// ----------------------------------------------------------------------------
+float DistributionGGX(vec3 N, vec3 H, float roughness)
+{
+ float a = roughness*roughness;
+ float a2 = a*a;
+ float NdotH = max(dot(N, H), 0.0);
+ float NdotH2 = NdotH*NdotH;
+
+ float nom = a2;
+ float denom = (NdotH2 * (a2 - 1.0) + 1.0);
+ denom = PI * denom * denom;
+
+ return nom / denom;
+}
+// ----------------------------------------------------------------------------
+// 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));
+}
+// ----------------------------------------------------------------------------
+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);
+
+ // from spherical coordinates to cartesian coordinates - halfway vector
+ vec3 H;
+ H.x = cos(phi) * sinTheta;
+ H.y = sin(phi) * sinTheta;
+ H.z = cosTheta;
+
+ // from tangent-space H vector to world-space 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);
+}
+// ----------------------------------------------------------------------------
+void main()
+{
+ vec3 N = normalize(WorldPos);
+
+ // make the simplyfying assumption that V equals R equals the normal
+ vec3 R = N;
+ vec3 V = R;
+
+ const uint SAMPLE_COUNT = 1024u;
+ vec3 prefilteredColor = vec3(0.0);
+ float totalWeight = 0.0;
+
+ for(uint i = 0u; i < SAMPLE_COUNT; ++i)
+ {
+ // generates a sample vector that's biased towards the preferred alignment direction (importance sampling).
+ 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)
+ {
+ // sample from the environment's mip level based on roughness/pdf
+ float D = DistributionGGX(N, H, roughness);
+ float NdotH = max(dot(N, H), 0.0);
+ float HdotV = max(dot(H, V), 0.0);
+ float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
+
+ //float resolution = 512.0; // resolution of source cubemap (per face)
+ float resolution = float(textureSize(environmentMap,0).x); // resolution of source cubemap (per face)
+ float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
+ float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
+
+ float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
+
+ prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
+ totalWeight += NdotL;
+ }
+ }
+
+ prefilteredColor = prefilteredColor / totalWeight;
+
+ FragColor = vec4(prefilteredColor, 1.0);
+}
diff --git a/ArchitectureColoredPainting/res/Shaders/final.frag b/ArchitectureColoredPainting/res/Shaders/final.frag
index 312e431..9618174 100644
--- a/ArchitectureColoredPainting/res/Shaders/final.frag
+++ b/ArchitectureColoredPainting/res/Shaders/final.frag
@@ -5,58 +5,16 @@ out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D gBaseColor;
-uniform sampler2D gNormal;
-uniform sampler2D gPosition;
-uniform sampler2D gMetallicRoughness;
-uniform sampler2D gDepth;
-uniform sampler2D gDirectLight;
-uniform sampler2D gIndirectLight;
+uniform float exposure = 1;
-uniform vec3 mainLightDirection;
-uniform vec3 mainLightRadiance;
-
-uniform vec3 camPos;
-
-const float PI = 3.14159265359;
-
-float DistributionGGX(vec3 N, vec3 H, float roughness)
+vec3 ACESToneMapping(vec3 color)
{
- float a = roughness*roughness;
- float a2 = a*a;
- float NdotH = max(dot(N, H), 0.0);
- float NdotH2 = NdotH*NdotH;
-
- float nom = a2;
- float denom = (NdotH2 * (a2 - 1.0) + 1.0);
- denom = PI * denom * denom;
-
- return nom / denom;
-}
-// ----------------------------------------------------------------------------
-float GeometrySchlickGGX(float NdotV, float roughness)
-{
- float r = (roughness + 1.0);
- float k = (r*r) / 8.0;
-
- float nom = NdotV;
- float denom = NdotV * (1.0 - k) + k;
-
- return nom / denom;
-}
-// ----------------------------------------------------------------------------
-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;
-}
-// ----------------------------------------------------------------------------
-vec3 fresnelSchlick(float cosTheta, vec3 F0)
-{
- return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
+ const float A = 2.51;
+ const float B = 0.03;
+ const float C = 2.43;
+ const float D = 0.59;
+ const float E = 0.14;
+ return (color * (A * color + B)) / (color * (C * color + D) + E);
}
void main()
@@ -81,7 +39,11 @@ void main()
discard;
}
vec3 color = 8 * rgbm.rgb * rgbm.a;
- color = color / (color + vec3(1.0));
+
+ color *= exposure;
+ color = ACESToneMapping(color);
+
+ //color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
FragColor = vec4(color, 1.0);
return;
diff --git a/ArchitectureColoredPainting/res/Shaders/irradiance_convolution.frag b/ArchitectureColoredPainting/res/Shaders/irradiance_convolution.frag
new file mode 100644
index 0000000..7e9e642
--- /dev/null
+++ b/ArchitectureColoredPainting/res/Shaders/irradiance_convolution.frag
@@ -0,0 +1,43 @@
+#version 450 core
+out vec4 FragColor;
+in vec3 WorldPos;
+
+uniform samplerCube environmentMap;
+
+const float PI = 3.14159265359;
+
+void main()
+{
+ // The world vector acts as the normal of a tangent surface
+ // from the origin, aligned to WorldPos. Given this normal, calculate all
+ // incoming radiance of the environment. The result of this radiance
+ // is the radiance of light coming from -Normal direction, which is what
+ // we use in the PBR shader to sample irradiance.
+ vec3 N = normalize(WorldPos);
+
+ vec3 irradiance = vec3(0.0);
+
+ // tangent space calculation from origin point
+ vec3 up = vec3(0.0, 1.0, 0.0);
+ vec3 right = normalize(cross(up, N));
+ up = normalize(cross(N, 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 (in tangent space)
+ 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 * N;
+
+ irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
+ nrSamples++;
+ }
+ }
+ irradiance = PI * irradiance * (1.0 / float(nrSamples));
+
+ FragColor = vec4(irradiance, 1.0);
+}
diff --git a/ArchitectureColoredPainting/res/Shaders/painting.comp b/ArchitectureColoredPainting/res/Shaders/painting.comp
index 5c5a82a..ce54b95 100644
--- a/ArchitectureColoredPainting/res/Shaders/painting.comp
+++ b/ArchitectureColoredPainting/res/Shaders/painting.comp
@@ -1258,7 +1258,7 @@ void main()
imageStore(gBaseColor, pixelLocation, vec4(color.rgb,1));
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
- //return;
+ return;
if (/*color.a!=-1&&*/debugBVH==vec3(0))
{
//imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));
diff --git a/ArchitectureColoredPainting/res/Shaders/shadow_mapping.comp b/ArchitectureColoredPainting/res/Shaders/shadow_mapping.comp
index f0b995f..a0a8cec 100644
--- a/ArchitectureColoredPainting/res/Shaders/shadow_mapping.comp
+++ b/ArchitectureColoredPainting/res/Shaders/shadow_mapping.comp
@@ -3,11 +3,15 @@
layout (local_size_x = 8, local_size_y = 8) in;
layout(rgba8, binding = 0) uniform image2D gBaseColor;
-//uniform sampler2D gBaseColor;
uniform sampler2D gNormal;
uniform sampler2D gPosition;
uniform sampler2D gMetallicRoughness;
uniform sampler2DArray gShadowMap;
+
+uniform samplerCube irradianceMap;
+uniform samplerCube prefilterMap;
+uniform sampler2D brdfLUT;
+
layout(rgba16f, binding = 1) uniform image2D gDirectLight;
layout (std140, binding = 0) uniform LightSpaceMatrices
{
@@ -66,6 +70,34 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
+vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
+{
+ return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
+}
+
+vec3 ambientLighting(vec3 N, vec3 V, vec3 F0, vec3 albedo,float metallic, float roughness, float ao)
+{
+ // ambient lighting (we now use IBL as the ambient term)
+ vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness);
+
+ vec3 kS = F;
+ vec3 kD = 1.0 - kS;
+ kD *= 1.0 - metallic;
+
+ vec3 irradiance = texture(irradianceMap, N).rgb;
+ vec3 diffuse = irradiance * albedo;
+
+ // sample both the pre-filter map and the BRDF lut and combine them together as per the Split-Sum approximation to get the IBL specular part.
+ const float MAX_REFLECTION_LOD = 4.0;
+ vec3 R = reflect(-V, N);
+ vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
+ vec2 brdf = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg;
+ vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
+
+ return (kD * diffuse + specular) * ao;
+}
+
+
const int pcfRadius = 3;
float getShadowFromLayer(vec3 fragPosWorldSpace, vec3 normal,int layer)
{
@@ -133,6 +165,8 @@ float ShadowCalculation(vec3 fragPosWorldSpace, vec3 normal, out int layer)
return shadow;
}
+
+
vec4 encodeRGBM(vec3 color)
{
if(dot(color,color)==0)
@@ -197,9 +231,11 @@ void main()
float NdotL = max(dot(normal, L), 0.0);
vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL;
+ vec3 ambient = ambientLighting(normal, V, F0, albedo, metallic, roughness, 1);
+
int debugLayer;
float shadow = ShadowCalculation(worldPos, normal, debugLayer);
- vec3 color = (1-shadow)*Lo + albedo*0.03;
+ vec3 color = (1-shadow)*Lo + ambient;
imageStore(gBaseColor, pixelLocation, encodeRGBM(color));
}
\ No newline at end of file
diff --git a/ArchitectureColoredPainting/res/Shaders/skybox.frag b/ArchitectureColoredPainting/res/Shaders/skybox.frag
index b2fde1e..fa086dd8 100644
--- a/ArchitectureColoredPainting/res/Shaders/skybox.frag
+++ b/ArchitectureColoredPainting/res/Shaders/skybox.frag
@@ -3,14 +3,30 @@ out vec4 FragColor;
in vec3 WorldPos;
uniform samplerCube environmentMap;
+uniform float exposure = 1;
+
+vec3 ACESToneMapping(vec3 color)
+{
+ const float A = 2.51;
+ const float B = 0.03;
+ const float C = 2.43;
+ const float D = 0.59;
+ const float E = 0.14;
+ return (color * (A * color + B)) / (color * (C * color + D) + E);
+}
void main()
{
- vec3 envColor = texture(environmentMap, WorldPos).rgb;
+ vec3 color = texture(environmentMap, WorldPos).rgb;
- // HDR tonemap and gamma correct
- envColor = envColor / (envColor + vec3(1.0));
- envColor = pow(envColor, vec3(1.0/2.2));
+ // HDR tonemap
+ //envColor = envColor / (envColor + vec3(1.0));
+
+ color *= exposure;
+ color = ACESToneMapping(color);
+
+ // gamma correct
+ color = pow(color, vec3(1.0/2.2));
- FragColor = vec4(envColor, 1.0);
+ FragColor = vec4(color, 1.0);
}
diff --git a/ArchitectureColoredPainting/src/Renderer/IblUtils.cpp b/ArchitectureColoredPainting/src/Renderer/IblUtils.cpp
new file mode 100644
index 0000000..b16c6f2
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Renderer/IblUtils.cpp
@@ -0,0 +1,324 @@
+#include "IblUtils.h"
+#include
+#include
+#include
+#define STB_IMAGE_IMPLEMENTATION
+#include
+
+void Renderer::IblUtils::renderCube(QOpenGLFunctions_4_5_Core* glFunc)
+{
+ static GLuint cubeVAO = 0, cubeVBO = 0;
+ // initialize (if necessary)
+ if (cubeVAO == 0)
+ {
+ float vertices[] = {
+ // back face
+ -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
+ 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
+ 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
+ 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
+ -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
+ -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left
+ // front face
+ -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
+ 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
+ 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
+ -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
+ -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
+ // left face
+ -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
+ -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
+ -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
+ -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
+ -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
+ -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
+ // right face
+ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
+ 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
+ 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
+ 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
+ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
+ 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
+ // bottom face
+ -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
+ 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
+ 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
+ 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
+ -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
+ -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
+ // top face
+ -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
+ 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
+ 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
+ 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
+ -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
+ -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
+ };
+ glFunc->glGenVertexArrays(1, &cubeVAO);
+ glFunc->glGenBuffers(1, &cubeVBO);
+ // fill buffer
+ glFunc->glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
+ glFunc->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+ // link vertex attributes
+ glFunc->glBindVertexArray(cubeVAO);
+ glFunc->glEnableVertexAttribArray(0);
+ glFunc->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
+ glFunc->glEnableVertexAttribArray(1);
+ glFunc->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
+ glFunc->glEnableVertexAttribArray(2);
+ glFunc->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
+ glFunc->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glFunc->glBindVertexArray(0);
+ }
+ // render Cube
+ glFunc->glBindVertexArray(cubeVAO);
+ glFunc->glDrawArrays(GL_TRIANGLES, 0, 36);
+ glFunc->glBindVertexArray(0);
+}
+
+std::tuple Renderer::IblUtils::precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc)
+{
+ // pbr: setup framebuffer
+ // ----------------------
+ unsigned int captureFBO;
+ unsigned int captureRBO;
+ glFunc->glGenFramebuffers(1, &captureFBO);
+ glFunc->glGenRenderbuffers(1, &captureRBO);
+
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ glFunc->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
+
+ // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions
+ // ----------------------------------------------------------------------------------------------
+ QMatrix4x4 captureProjection;
+ captureProjection.perspective(90.0f, 1.0f, 0.1f, 10.0f);
+ std::array captureViews;
+ captureViews[0].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(1.0f, 0.0f, 0.0f), QVector3D(0.0f, -1.0f, 0.0f));
+ captureViews[1].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(-1.0f, 0.0f, 0.0f), QVector3D(0.0f, -1.0f, 0.0f));
+ captureViews[2].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f), QVector3D(0.0f, 0.0f, 1.0f));
+ captureViews[3].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, -1.0f, 0.0f), QVector3D(0.0f, 0.0f, -1.0f));
+ captureViews[4].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 0.0f, 1.0f), QVector3D(0.0f, -1.0f, 0.0f));
+ captureViews[5].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 0.0f, -1.0f), QVector3D(0.0f, -1.0f, 0.0f));
+
+ GLuint envCubemap = generateCubemap(glFunc, captureFBO, captureRBO, captureProjection, captureViews);
+ GLuint irradianceMap = generateIrradianceMap(glFunc, captureFBO, captureRBO, captureProjection, captureViews, envCubemap);
+ GLuint prefilterMap = generatePrefilterMap(glFunc, captureFBO, captureRBO, captureProjection, captureViews, envCubemap);
+ GLuint brdfLut = gererateBrdfLut(glFunc);
+ return { envCubemap, irradianceMap, prefilterMap, brdfLut };
+}
+
+GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews)
+{
+ // pbr: load the HDR environment map
+ // ---------------------------------
+ stbi_set_flip_vertically_on_load(true);
+ int width, height, nrComponents;
+ float* data = stbi_loadf("HDRI/clarens_midday_4k.hdr", &width, &height, &nrComponents, 0);
+ unsigned int hdrTexture = 0;
+ if (data)
+ {
+ glGenTextures(1, &hdrTexture);
+ glBindTexture(GL_TEXTURE_2D, hdrTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data);
+
+ 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);
+
+ stbi_image_free(data);
+ }
+ else
+ qDebug() << "Failed to load HDR image.";
+
+ // pbr: setup cubemap to render to and attach to framebuffer
+ // ---------------------------------------------------------
+ unsigned int envCubemap;
+ glFunc->glGenTextures(1, &envCubemap);
+ glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ glFunc->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, cubemapSize, cubemapSize, 0, GL_RGB, GL_FLOAT, nullptr);
+ }
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+
+ // pbr: convert HDR equirectangular environment map to cubemap equivalent
+ // ----------------------------------------------------------------------
+ QOpenGLShaderProgram shader;
+ if (!shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/cubemap.vert"))
+ qDebug() << "ERROR:" << shader.log();
+ if (!shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/cubemap.frag"))
+ qDebug() << "ERROR:" << shader.log();
+ if (!shader.link())
+ qDebug() << "ERROR:" << shader.log();
+ shader.bind();
+ shader.setUniformValue("equirectangularMap", 0);
+ shader.setUniformValue("projection", captureProjection);
+ glFunc->glActiveTexture(GL_TEXTURE0);
+ glFunc->glBindTexture(GL_TEXTURE_2D, hdrTexture);
+
+ glFunc->glViewport(0, 0, cubemapSize, cubemapSize);
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+
+
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ shader.setUniformValue("view", captureViews[i]);
+ glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0);
+ glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ renderCube(glFunc);
+ }
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return envCubemap;
+}
+
+GLuint Renderer::IblUtils::generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews, GLuint envCubemap)
+{
+ constexpr int irradianceMapSize = 32;
+
+ // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale.
+ // --------------------------------------------------------------------------------
+ unsigned int irradianceMap;
+ glFunc->glGenTextures(1, &irradianceMap);
+ glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ glFunc->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, irradianceMapSize, irradianceMapSize, 0, GL_RGB, GL_FLOAT, nullptr);
+ }
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
+ glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, irradianceMapSize, irradianceMapSize);
+
+ // pbr: solve diffuse integral by convolution to create an irradiance (cube)map.
+ // -----------------------------------------------------------------------------
+ QOpenGLShaderProgram irradianceShader;
+ if (!irradianceShader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/cubemap.vert"))
+ qDebug() << "ERROR:" << irradianceShader.log();
+ if (!irradianceShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/irradiance_convolution.frag"))
+ qDebug() << "ERROR:" << irradianceShader.log();
+ if (!irradianceShader.link())
+ qDebug() << "ERROR:" << irradianceShader.log();
+ irradianceShader.bind();
+ irradianceShader.setUniformValue("environmentMap", 0);
+ irradianceShader.setUniformValue("projection", captureProjection);
+ glFunc->glActiveTexture(GL_TEXTURE0);
+ glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
+
+ glFunc->glViewport(0, 0, irradianceMapSize, irradianceMapSize); // don't forget to configure the viewport to the capture dimensions.
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ irradianceShader.setUniformValue("view", captureViews[i]);
+ glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0);
+ glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ renderCube(glFunc);
+ }
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return irradianceMap;
+}
+
+GLuint Renderer::IblUtils::generatePrefilterMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews, GLuint envCubemap)
+{
+ constexpr int prefilterMapSize = 128;
+
+ // pbr: create a pre-filter cubemap, and re-scale capture FBO to pre-filter scale.
+ // --------------------------------------------------------------------------------
+ unsigned int prefilterMap;
+ glFunc->glGenTextures(1, &prefilterMap);
+ glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ glFunc->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, prefilterMapSize, prefilterMapSize, 0, GL_RGB, GL_FLOAT, nullptr);
+ }
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // be sure to set minification filter to mip_linear
+ glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // generate mipmaps for the cubemap so OpenGL automatically allocates the required memory.
+ glFunc->glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+
+ // pbr: run a quasi monte-carlo simulation on the environment lighting to create a prefilter (cube)map.
+ // ----------------------------------------------------------------------------------------------------
+ QOpenGLShaderProgram prefilterShader;
+ if (!prefilterShader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/cubemap.vert"))
+ qDebug() << "ERROR:" << prefilterShader.log();
+ if (!prefilterShader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/cubemap_prefilter.frag"))
+ qDebug() << "ERROR:" << prefilterShader.log();
+ if (!prefilterShader.link())
+ qDebug() << "ERROR:" << prefilterShader.log();
+ prefilterShader.bind();
+ prefilterShader.setUniformValue("environmentMap", 0);
+ prefilterShader.setUniformValue("projection", captureProjection);
+ glFunc->glActiveTexture(GL_TEXTURE0);
+ glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
+
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ unsigned int maxMipLevels = 5;
+ for (unsigned int mip = 0; mip < maxMipLevels; ++mip)
+ {
+ // reisze framebuffer according to mip-level size.
+ unsigned int mipWidth = static_cast(prefilterMapSize * std::pow(0.5, mip));
+ unsigned int mipHeight = static_cast(prefilterMapSize * std::pow(0.5, mip));
+ glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
+ glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
+ glFunc->glViewport(0, 0, mipWidth, mipHeight);
+
+ float roughness = (float)mip / (float)(maxMipLevels - 1);
+ prefilterShader.setUniformValue("roughness", roughness);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ prefilterShader.setUniformValue("view", captureViews[i]);
+ glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip);
+
+ glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ renderCube(glFunc);
+ }
+ }
+ glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ return prefilterMap;
+}
+
+GLuint Renderer::IblUtils::gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc)
+{
+ constexpr int lutSize = 512;
+
+ // pbr: generate a 2D LUT from the BRDF equations used.
+ // ----------------------------------------------------
+ unsigned int brdfLUTTexture;
+ glFunc->glGenTextures(1, &brdfLUTTexture);
+
+ // pre-allocate enough memory for the LUT texture.
+ glFunc->glBindTexture(GL_TEXTURE_2D, brdfLUTTexture);
+ glFunc->glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, lutSize, lutSize, 0, GL_RG, GL_FLOAT, 0);
+ // be sure to set wrapping mode to GL_CLAMP_TO_EDGE
+ glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ QOpenGLShaderProgram brdfShader;
+ if (!brdfShader.addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/brdf_lut.comp"))
+ qDebug() << "ERROR:" << brdfShader.log();
+ if (!brdfShader.link())
+ qDebug() << "ERROR:" << brdfShader.log();
+ brdfShader.bind();
+ glFunc->glBindImageTexture(0, brdfLUTTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RG16F);
+ glFunc->glDispatchCompute(ceil(lutSize / 8.), ceil(lutSize / 8.), 1);
+ brdfShader.release();
+ return brdfLUTTexture;
+}
diff --git a/ArchitectureColoredPainting/src/Renderer/IblUtils.h b/ArchitectureColoredPainting/src/Renderer/IblUtils.h
new file mode 100644
index 0000000..fdfb56b
--- /dev/null
+++ b/ArchitectureColoredPainting/src/Renderer/IblUtils.h
@@ -0,0 +1,23 @@
+#pragma once
+#include
+
+namespace Renderer
+{
+ class IblUtils
+ {
+ public:
+ static constexpr int cubemapSize = 1024;
+ static void renderCube(QOpenGLFunctions_4_5_Core* glFunc);
+ /**
+ * @brief
+ * @return GLuint envCubemap
+ * @return GLuint irradianceMap
+ */
+ static std::tuple precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc);
+ private:
+ static GLuint generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews);
+ static GLuint generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews, GLuint envCubemap);
+ static GLuint generatePrefilterMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array& captureViews, GLuint envCubemap);
+ static GLuint gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc);
+ };
+}
diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/ElementStyle.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/ElementStyle.cpp
index 262b456..cf1f722 100644
--- a/ArchitectureColoredPainting/src/Renderer/Painting/ElementStyle.cpp
+++ b/ArchitectureColoredPainting/src/Renderer/Painting/ElementStyle.cpp
@@ -7,7 +7,7 @@ using namespace Renderer;
std::vector Renderer::ElementStyleFillDemo::toBaseStyles() const
{
return { BaseStyle(std::make_shared(),
- std::make_shared(std::make_shared(QColor(0, 255, 0), 0, 0.8))) };
+ std::make_shared(std::make_shared(QColor(202, 148, 44), 1, 0.18))) };
}
Renderer::ElementStyleStrokeDemo::ElementStyleStrokeDemo(float width)
diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.cpp b/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.cpp
index f0d7caf..368d5e6 100644
--- a/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.cpp
+++ b/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.cpp
@@ -1,7 +1,7 @@
#include "PaintingHelper.h"
using namespace Renderer;
-PaintingHelper::PaintingHelper(QOpenGLFunctions_4_5_Compatibility* glFunc) :glFunc(glFunc)
+PaintingHelper::PaintingHelper(QOpenGLFunctions_4_5_Core* glFunc) :glFunc(glFunc)
{
}
diff --git a/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.h b/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.h
index dbd66fe..ea0faee 100644
--- a/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.h
+++ b/ArchitectureColoredPainting/src/Renderer/Painting/PaintingHelper.h
@@ -3,7 +3,7 @@
#include
#include
#include
-#include
+#include
#include "BvhTree.h"
#include "Painting.h"
namespace Renderer
@@ -11,7 +11,7 @@ namespace Renderer
class PaintingHelper
{
private:
- QOpenGLFunctions_4_5_Compatibility* glFunc;
+ QOpenGLFunctions_4_5_Core* glFunc;
GLuint paintingOffsetsSSBO, bvhSSBO, bvhBoundSSBO, elementOffsetSSBO, elementIndexSSBO, elementDataSSBO;
std::vector paintingOffsets;
std::vector bvhChildren;
@@ -22,7 +22,7 @@ namespace Renderer
int paintingCount = 0;
public:
- PaintingHelper(QOpenGLFunctions_4_5_Compatibility* glFunc);
+ PaintingHelper(QOpenGLFunctions_4_5_Core* glFunc);
int addPainting(Painting painting);
int addPainting(std::vector bvhChildren, std::vector bvhBound,
std::vector elementOffset, std::vector elementIndex, std::vector elementData);
diff --git a/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.cpp b/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.cpp
index 374b4f9..0507472 100644
--- a/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.cpp
+++ b/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.cpp
@@ -7,12 +7,11 @@
#include
#include
#include
-#define STB_IMAGE_IMPLEMENTATION
-#include
+#include "IblUtils.h"
using namespace Renderer;
-//QVector3D lightPositions[] = { 2000 * QVector3D(0.2, 4, 1).normalized(), QVector3D(100,100,100) ,QVector3D(-100,100,100) ,QVector3D(100,100,-100) };
-QVector3D lightColors[] = { 20 * QVector3D(0.7529,0.7450,0.6784).normalized(), QVector3D(0,0,0) ,QVector3D(0,0,0) ,QVector3D(0,0,0) };
+
+QVector3D mainLightRadiance = 40 * QVector3D(0.7529, 0.7450, 0.6784).normalized();
static float sunPitch = 105, sunYaw = 80;
static int sunSpeed = 10;
@@ -92,181 +91,24 @@ void RendererGLWidget::setMainLightYaw(float yaw)
//qDebug() << "yaw" << yaw;
sunYaw = yaw;
}
+
+void Renderer::RendererGLWidget::setExposure(float exposure)
+{
+ this->exposure = exposure;
+}
+
QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
-void renderCube(QOpenGLFunctions_4_5_Compatibility* glFunc)
-{
- static GLuint cubeVAO = 0, cubeVBO = 0;
- // initialize (if necessary)
- if (cubeVAO == 0)
- {
- float vertices[] = {
- // back face
- -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
- 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
- 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, // bottom-right
- 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, // top-right
- -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, // bottom-left
- -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, // top-left
- // front face
- -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
- 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // bottom-right
- 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
- 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, // top-right
- -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // top-left
- -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom-left
- // left face
- -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
- -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-left
- -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
- -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-left
- -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-right
- -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-right
- // right face
- 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
- 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
- 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top-right
- 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom-right
- 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, // top-left
- 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, // bottom-left
- // bottom face
- -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
- 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, // top-left
- 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
- 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom-left
- -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom-right
- -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, // top-right
- // top face
- -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
- 1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
- 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top-right
- 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom-right
- -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top-left
- -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
- };
- glFunc->glGenVertexArrays(1, &cubeVAO);
- glFunc->glGenBuffers(1, &cubeVBO);
- // fill buffer
- glFunc->glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
- glFunc->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- // link vertex attributes
- glFunc->glBindVertexArray(cubeVAO);
- glFunc->glEnableVertexAttribArray(0);
- glFunc->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
- glFunc->glEnableVertexAttribArray(1);
- glFunc->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
- glFunc->glEnableVertexAttribArray(2);
- glFunc->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
- glFunc->glBindBuffer(GL_ARRAY_BUFFER, 0);
- glFunc->glBindVertexArray(0);
- }
- // render Cube
- glFunc->glBindVertexArray(cubeVAO);
- glFunc->glDrawArrays(GL_TRIANGLES, 0, 36);
- glFunc->glBindVertexArray(0);
-}
-
-GLuint generateCubemap(QOpenGLFunctions_4_5_Compatibility* glFunc)
-{
- QOpenGLShaderProgram shader;
- if (!shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/cubemap.vert"))
- qDebug() << "ERROR:" << shader.log();
- if (!shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/cubemap.frag"))
- qDebug() << "ERROR:" << shader.log();
- if (!shader.link())
- qDebug() << "ERROR:" << shader.log();
- // pbr: setup framebuffer
- // ----------------------
- unsigned int captureFBO;
- unsigned int captureRBO;
- glFunc->glGenFramebuffers(1, &captureFBO);
- glFunc->glGenRenderbuffers(1, &captureRBO);
-
- glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
- glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
- glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 1024, 1024);
- glFunc->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
-
- // pbr: load the HDR environment map
- // ---------------------------------
- stbi_set_flip_vertically_on_load(true);
- int width, height, nrComponents;
- float* data = stbi_loadf("HDRI/clarens_midday_4k.hdr", &width, &height, &nrComponents, 0);
- unsigned int hdrTexture;
- if (data)
- {
- glGenTextures(1, &hdrTexture);
- glBindTexture(GL_TEXTURE_2D, hdrTexture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data);
-
- 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);
-
- stbi_image_free(data);
- }
- else
- std::cout << "Failed to load HDR image." << std::endl;
-
- // pbr: setup cubemap to render to and attach to framebuffer
- // ---------------------------------------------------------
- unsigned int envCubemap;
- glFunc->glGenTextures(1, &envCubemap);
- glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
- for (unsigned int i = 0; i < 6; ++i)
- {
- glFunc->glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr);
- }
- glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions
- // ----------------------------------------------------------------------------------------------
- QMatrix4x4 captureProjection;
- captureProjection.perspective(90.0f, 1.0f, 0.1f, 10.0f);
-
- QMatrix4x4 captureViews[6];
- captureViews[0].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D( 1.0f, 0.0f, 0.0f), QVector3D(0.0f, -1.0f, 0.0f));
- captureViews[1].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(-1.0f, 0.0f, 0.0f), QVector3D(0.0f, -1.0f, 0.0f));
- captureViews[2].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D( 0.0f, 1.0f, 0.0f), QVector3D(0.0f, 0.0f, 1.0f));
- captureViews[3].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D( 0.0f, -1.0f, 0.0f), QVector3D(0.0f, 0.0f, -1.0f));
- captureViews[4].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D( 0.0f, 0.0f, 1.0f), QVector3D(0.0f, -1.0f, 0.0f));
- captureViews[5].lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D( 0.0f, 0.0f, -1.0f), QVector3D(0.0f, -1.0f, 0.0f));
-
- // pbr: convert HDR equirectangular environment map to cubemap equivalent
- // ----------------------------------------------------------------------
- shader.bind();
- shader.setUniformValue("equirectangularMap", 0);
- shader.setUniformValue("projection", captureProjection);
- glFunc->glActiveTexture(GL_TEXTURE0);
- glFunc->glBindTexture(GL_TEXTURE_2D, hdrTexture);
-
- glFunc->glViewport(0, 0, 512, 512); // don't forget to configure the viewport to the capture dimensions.
- glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
- for (unsigned int i = 0; i < 6; ++i)
- {
- shader.setUniformValue("view", captureViews[i]);
- glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0);
- glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- renderCube(glFunc);
- }
- glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0);
- return envCubemap;
-}
-
void RendererGLWidget::initializeGL()
{
initializeOpenGLFunctions();
+ QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions();
qDebug() << "GL_VERSION" << (char*)glGetString(GL_VERSION);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
glClearColor(0, 0, 0, 1);
shadowProgramPtr = new QOpenGLShaderProgram;
@@ -360,6 +202,9 @@ void RendererGLWidget::initializeGL()
shadowMappingProgramPtr->setUniformValue("gPosition", 2);
shadowMappingProgramPtr->setUniformValue("gMetallicRoughness", 3);
shadowMappingProgramPtr->setUniformValue("gShadowMap", 4);
+ shadowMappingProgramPtr->setUniformValue("irradianceMap", 5);
+ shadowMappingProgramPtr->setUniformValue("prefilterMap", 6);
+ shadowMappingProgramPtr->setUniformValue("brdfLUT", 7);
shadowMappingProgramPtr->release();
ssgiProgramPtr->bind();
@@ -372,46 +217,15 @@ void RendererGLWidget::initializeGL()
finalProgramPtr->bind();
finalProgramPtr->setUniformValue("gBaseColor", 0);
- finalProgramPtr->setUniformValue("gDirectLight", 1);
- finalProgramPtr->setUniformValue("gIndirectLight", 2);
- /*finalProgramPtr->setUniformValue("gNormal", 1);
- finalProgramPtr->setUniformValue("gPosition", 2);
- finalProgramPtr->setUniformValue("gMetallicRoughness", 3);
- finalProgramPtr->setUniformValue("gDepth", 4);
- finalProgramPtr->setUniformValue("gDirectLight", 5);*/
-
-
-
- //std::vector rsmSampleCoordsAndWeights;
- //std::default_random_engine e;
- //std::uniform_real_distribution u(0, 1);
- //int rsmSampleNum = 50;
- //finalProgramPtr->setUniformValue("rsmSampleNum", rsmSampleNum);
- //for (int i = 0; i < rsmSampleNum; ++i)
- //{
- // float xi1 = u(e);
- // float xi2 = u(e);
- // rsmSampleCoordsAndWeights.push_back(QVector3D(xi1 * sin(2 * M_PI * xi2), xi1 * cos(2 * M_PI * xi2), xi1 * xi1));
- //}
- ////QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
- //randomMap.create();
- //randomMap.setSize(rsmSampleCoordsAndWeights.size());
- //randomMap.setFormat(QOpenGLTexture::RGB8_UNorm);
- //randomMap.allocateStorage();
- //randomMap.setData(QOpenGLTexture::RGB, QOpenGLTexture::Float32, rsmSampleCoordsAndWeights.data());
- //randomMap.setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Nearest);
-
-
finalProgramPtr->release();
- paintingHelper = new PaintingHelper(QOpenGLContext::currentContext()->versionFunctions());
+ paintingHelper = new PaintingHelper(glFunc);
model = new Model(context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
skyBoxProgramPtr->bind();
skyBoxProgramPtr->setUniformValue("environmentMap", 0);
skyBoxProgramPtr->release();
- skyCubemap = generateCubemap(QOpenGLContext::currentContext()->versionFunctions());
-
+ std::tie(skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture) = IblUtils::precomputeCubemaps(glFunc);
quadVAO.create();
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
@@ -442,6 +256,8 @@ void RendererGLWidget::initializeGL()
void RendererGLWidget::paintGL()
{
+ QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions();
+
glEnable(GL_CULL_FACE);
light.lightDirection.setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
@@ -532,7 +348,7 @@ void RendererGLWidget::paintGL()
shadowMappingProgramPtr->setUniformValue("shadowBlendRatio", light.blendRatio);
shadowMappingProgramPtr->setUniformValue("camPos", camera.Position);
shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
- shadowMappingProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);
+ shadowMappingProgramPtr->setUniformValue("mainLightRadiance", mainLightRadiance);
/*glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gbuffers[0]);*/
glActiveTexture(GL_TEXTURE1);
@@ -543,6 +359,12 @@ void RendererGLWidget::paintGL()
glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
+ 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);
glBindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glBindImageTexture(1, gbuffers[8], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F);
glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
@@ -576,25 +398,9 @@ void RendererGLWidget::paintGL()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
finalProgramPtr->bind();
- /*finalProgramPtr->setUniformValue("camPos", camera.Position);
- finalProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
- finalProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);*/
+ finalProgramPtr->setUniformValue("exposure", exposure);
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gbuffers[0]);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, gbuffers[8]);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, gbuffers[9]);
- //glActiveTexture(GL_TEXTURE1);
- //glBindTexture(GL_TEXTURE_2D, gbuffers[1]);
- //glActiveTexture(GL_TEXTURE2);
- //glBindTexture(GL_TEXTURE_2D, gbuffers[2]);
- //glActiveTexture(GL_TEXTURE3);
- //glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
- //glActiveTexture(GL_TEXTURE4);
- //glBindTexture(GL_TEXTURE_2D, gbuffers[7]);
- //glActiveTexture(GL_TEXTURE5);
- //glBindTexture(GL_TEXTURE_2D, gbuffers[8]);
+ glBindTexture(GL_TEXTURE_2D, gbuffers[0]);
quadVAO.bind();
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
quadVAO.release();
@@ -603,10 +409,11 @@ void RendererGLWidget::paintGL()
skyBoxProgramPtr->bind();
glDisable(GL_CULL_FACE);
skyBoxProgramPtr->setUniformValue("view", view);
- skyBoxProgramPtr->setUniformValue("projection", projection);
+ skyBoxProgramPtr->setUniformValue("projection", projection);
+ skyBoxProgramPtr->setUniformValue("exposure", exposure);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyCubemap);
- renderCube(QOpenGLContext::currentContext()->versionFunctions());
+ IblUtils::renderCube(glFunc);
skyBoxProgramPtr->release();
GLuint paintingCompDuration;
diff --git a/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.h b/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.h
index ec1fee8..6fa8d5e 100644
--- a/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.h
+++ b/ArchitectureColoredPainting/src/Renderer/RendererGLWidget.h
@@ -1,7 +1,7 @@
#pragma once
#include
-#include
+#include
#include
#include
#include
@@ -13,7 +13,7 @@
#include "Painting/PaintingHelper.h"
namespace Renderer
{
- class RendererGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Compatibility
+ class RendererGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core
{
Q_OBJECT
public:
@@ -26,6 +26,7 @@ namespace Renderer
void setModel();
void setMainLightPitch(float pitch);
void setMainLightYaw(float yaw);
+ void setExposure(float exposure);
protected:
void initializeGL() override;
void paintGL() override;
@@ -47,6 +48,7 @@ namespace Renderer
clock_t lastFrame;
float deltaTime;
int shadowMapResolution;
+ float exposure = 0.8;
QOpenGLShaderProgram* shadowProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr;
@@ -64,6 +66,9 @@ namespace Renderer
GLuint shadowGbuffer;
GLuint lightSpaceMatricesUBO;
GLuint skyCubemap;
+ GLuint irradianceMap;
+ GLuint prefilterMap;
+ GLuint brdfLUTTexture;
QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO;
Model* model = nullptr;
diff --git a/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp b/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp
index 5e295ea..b478df7 100644
--- a/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp
+++ b/ArchitectureColoredPainting/src/Renderer/RendererWidget.cpp
@@ -9,8 +9,13 @@ RendererWidget::RendererWidget(QWidget *parent)
ui.openGLWidget, &RendererGLWidget::setMainLightPitch);
QObject::connect(ui.horizontalSlider_2, &QSlider::valueChanged,
ui.openGLWidget, &RendererGLWidget::setMainLightYaw);
+ QObject::connect(ui.exposureSlider, &QSlider::valueChanged, [&](int value) {
+ ui.openGLWidget->setExposure(value/100.f);
+ });
+
ui.horizontalSlider->setValue(105);
ui.horizontalSlider_2->setValue(80);
+ ui.exposureSlider->setValue(60);
QObject::connect(ui.openButton, &QPushButton::clicked,
ui.openGLWidget, &RendererGLWidget::setModel);
}
diff --git a/README.md b/README.md
index 8b212e5..b5ef6ff 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@
### 场景渲染(Renderer)
-采用 PBR (金属度-粗糙度) 材质模型,场景中存在一个方向光,可拖动滑动条调整光源方向观察材质效果
+采用 PBR (金属度-粗糙度) 材质模型
已实现由图元数据建立完整彩绘编码