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 (金属度-粗糙度) 材质模型 已实现由图元数据建立完整彩绘编码