实现IBL
parent
f3559d133d
commit
2a78bb4be8
|
@ -121,6 +121,7 @@
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
<ClCompile Include="src\MainWindow.cpp" />
|
<ClCompile Include="src\MainWindow.cpp" />
|
||||||
<ClCompile Include="src\NavigationBarWidget.cpp" />
|
<ClCompile Include="src\NavigationBarWidget.cpp" />
|
||||||
|
<ClCompile Include="src\Renderer\IblUtils.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\BaseStyle.cpp" />
|
<ClCompile Include="src\Renderer\Painting\BaseStyle.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Painting\BvhTree.cpp" />
|
<ClCompile Include="src\Renderer\Painting\BvhTree.cpp" />
|
||||||
<ClCompile Include="src\Renderer\Camera.cpp" />
|
<ClCompile Include="src\Renderer\Camera.cpp" />
|
||||||
|
@ -154,13 +155,16 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\data.json" />
|
<None Include="..\data.json" />
|
||||||
|
<None Include="res\Shaders\brdf_lut.comp" />
|
||||||
<None Include="res\Shaders\cubemap.frag" />
|
<None Include="res\Shaders\cubemap.frag" />
|
||||||
<None Include="res\Shaders\cubemap.vert" />
|
<None Include="res\Shaders\cubemap.vert" />
|
||||||
|
<None Include="res\Shaders\cubemap_prefilter.frag" />
|
||||||
<None Include="res\Shaders\depth_init.comp" />
|
<None Include="res\Shaders\depth_init.comp" />
|
||||||
<None Include="res\Shaders\depth_mipmap.comp" />
|
<None Include="res\Shaders\depth_mipmap.comp" />
|
||||||
<None Include="res\Shaders\element.comp" />
|
<None Include="res\Shaders\element.comp" />
|
||||||
<None Include="res\Shaders\final.frag" />
|
<None Include="res\Shaders\final.frag" />
|
||||||
<None Include="res\Shaders\final.vert" />
|
<None Include="res\Shaders\final.vert" />
|
||||||
|
<None Include="res\Shaders\irradiance_convolution.frag" />
|
||||||
<None Include="res\Shaders\model.frag" />
|
<None Include="res\Shaders\model.frag" />
|
||||||
<None Include="res\Shaders\model.vert" />
|
<None Include="res\Shaders\model.vert" />
|
||||||
<None Include="res\Shaders\model_shadow.frag" />
|
<None Include="res\Shaders\model_shadow.frag" />
|
||||||
|
@ -192,6 +196,7 @@
|
||||||
<ClInclude Include="src\Editor\ThirdPartyLib\SvgHelper.h" />
|
<ClInclude Include="src\Editor\ThirdPartyLib\SvgHelper.h" />
|
||||||
<ClInclude Include="src\Editor\util\PainterPathUtil.h" />
|
<ClInclude Include="src\Editor\util\PainterPathUtil.h" />
|
||||||
<ClInclude Include="src\Editor\util\SvgFileLoader.h" />
|
<ClInclude Include="src\Editor\util\SvgFileLoader.h" />
|
||||||
|
<ClInclude Include="src\Renderer\IblUtils.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\CubicBezierSignedDistance.h" />
|
<ClInclude Include="src\Renderer\Painting\CubicBezierSignedDistance.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\Element.h" />
|
<ClInclude Include="src\Renderer\Painting\Element.h" />
|
||||||
<ClInclude Include="src\Renderer\Painting\ElementStyle.h" />
|
<ClInclude Include="src\Renderer\Painting\ElementStyle.h" />
|
||||||
|
|
|
@ -210,6 +210,9 @@
|
||||||
<ClCompile Include="src\Editor\LayerStyle.cpp">
|
<ClCompile Include="src\Editor\LayerStyle.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\Renderer\IblUtils.cpp">
|
||||||
|
<Filter>Source Files\Renderer</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
<QtMoc Include="src\Renderer\RendererGLWidget.h">
|
||||||
|
@ -311,6 +314,15 @@
|
||||||
<None Include="res\Shaders\skybox.frag">
|
<None Include="res\Shaders\skybox.frag">
|
||||||
<Filter>Resource Files\Shaders</Filter>
|
<Filter>Resource Files\Shaders</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="res\Shaders\irradiance_convolution.frag">
|
||||||
|
<Filter>Resource Files\Shaders</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="res\Shaders\cubemap_prefilter.frag">
|
||||||
|
<Filter>Resource Files\Shaders</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="res\Shaders\brdf_lut.comp">
|
||||||
|
<Filter>Resource Files\Shaders</Filter>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtUic Include="EditorWidget.ui">
|
<QtUic Include="EditorWidget.ui">
|
||||||
|
@ -423,6 +435,9 @@
|
||||||
<ClInclude Include="src\Editor\PixelPath.h">
|
<ClInclude Include="src\Editor\PixelPath.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\Renderer\IblUtils.h">
|
||||||
|
<Filter>Header Files\Renderer</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtRcc Include="res\MainWindow.qrc">
|
<QtRcc Include="res\MainWindow.qrc">
|
||||||
|
|
|
@ -115,11 +115,20 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>12</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QSlider" name="horizontalSlider">
|
<widget class="QSlider" name="horizontalSlider">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
|
@ -128,7 +137,7 @@
|
||||||
<number>180</number>
|
<number>180</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -138,7 +147,23 @@
|
||||||
<number>360</number>
|
<number>360</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSlider" name="exposureSlider">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>200</number>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
<file>Shaders/cubemap.vert</file>
|
<file>Shaders/cubemap.vert</file>
|
||||||
<file>Shaders/skybox.frag</file>
|
<file>Shaders/skybox.frag</file>
|
||||||
<file>Shaders/skybox.vert</file>
|
<file>Shaders/skybox.vert</file>
|
||||||
|
<file>Shaders/irradiance_convolution.frag</file>
|
||||||
|
<file>Shaders/cubemap_prefilter.frag</file>
|
||||||
|
<file>Shaders/brdf_lut.comp</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/qt/etc">
|
<qresource prefix="/qt/etc">
|
||||||
<file>qt.conf</file>
|
<file>qt.conf</file>
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -5,58 +5,16 @@ out vec4 FragColor;
|
||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
|
|
||||||
uniform sampler2D gBaseColor;
|
uniform sampler2D gBaseColor;
|
||||||
uniform sampler2D gNormal;
|
uniform float exposure = 1;
|
||||||
uniform sampler2D gPosition;
|
|
||||||
uniform sampler2D gMetallicRoughness;
|
|
||||||
uniform sampler2D gDepth;
|
|
||||||
uniform sampler2D gDirectLight;
|
|
||||||
uniform sampler2D gIndirectLight;
|
|
||||||
|
|
||||||
uniform vec3 mainLightDirection;
|
vec3 ACESToneMapping(vec3 color)
|
||||||
uniform vec3 mainLightRadiance;
|
|
||||||
|
|
||||||
uniform vec3 camPos;
|
|
||||||
|
|
||||||
const float PI = 3.14159265359;
|
|
||||||
|
|
||||||
float DistributionGGX(vec3 N, vec3 H, float roughness)
|
|
||||||
{
|
{
|
||||||
float a = roughness*roughness;
|
const float A = 2.51;
|
||||||
float a2 = a*a;
|
const float B = 0.03;
|
||||||
float NdotH = max(dot(N, H), 0.0);
|
const float C = 2.43;
|
||||||
float NdotH2 = NdotH*NdotH;
|
const float D = 0.59;
|
||||||
|
const float E = 0.14;
|
||||||
float nom = a2;
|
return (color * (A * color + B)) / (color * (C * color + D) + E);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
@ -81,7 +39,11 @@ void main()
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
vec3 color = 8 * rgbm.rgb * rgbm.a;
|
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));
|
color = pow(color, vec3(1.0/2.2));
|
||||||
FragColor = vec4(color, 1.0);
|
FragColor = vec4(color, 1.0);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -1258,7 +1258,7 @@ void main()
|
||||||
|
|
||||||
imageStore(gBaseColor, pixelLocation, vec4(color.rgb,1));
|
imageStore(gBaseColor, pixelLocation, vec4(color.rgb,1));
|
||||||
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
|
imageStore(gMetallicRoughness, pixelLocation, vec4(metallicRoughness, 0, 1));
|
||||||
//return;
|
return;
|
||||||
if (/*color.a!=-1&&*/debugBVH==vec3(0))
|
if (/*color.a!=-1&&*/debugBVH==vec3(0))
|
||||||
{
|
{
|
||||||
//imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));
|
//imageStore(gBaseColor, pixelLocation, vec4(vec3(1, 1, 0),1));
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
layout (local_size_x = 8, local_size_y = 8) in;
|
layout (local_size_x = 8, local_size_y = 8) in;
|
||||||
|
|
||||||
layout(rgba8, binding = 0) uniform image2D gBaseColor;
|
layout(rgba8, binding = 0) uniform image2D gBaseColor;
|
||||||
//uniform sampler2D gBaseColor;
|
|
||||||
uniform sampler2D gNormal;
|
uniform sampler2D gNormal;
|
||||||
uniform sampler2D gPosition;
|
uniform sampler2D gPosition;
|
||||||
uniform sampler2D gMetallicRoughness;
|
uniform sampler2D gMetallicRoughness;
|
||||||
uniform sampler2DArray gShadowMap;
|
uniform sampler2DArray gShadowMap;
|
||||||
|
|
||||||
|
uniform samplerCube irradianceMap;
|
||||||
|
uniform samplerCube prefilterMap;
|
||||||
|
uniform sampler2D brdfLUT;
|
||||||
|
|
||||||
layout(rgba16f, binding = 1) uniform image2D gDirectLight;
|
layout(rgba16f, binding = 1) uniform image2D gDirectLight;
|
||||||
layout (std140, binding = 0) uniform LightSpaceMatrices
|
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);
|
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;
|
const int pcfRadius = 3;
|
||||||
float getShadowFromLayer(vec3 fragPosWorldSpace, vec3 normal,int layer)
|
float getShadowFromLayer(vec3 fragPosWorldSpace, vec3 normal,int layer)
|
||||||
{
|
{
|
||||||
|
@ -133,6 +165,8 @@ float ShadowCalculation(vec3 fragPosWorldSpace, vec3 normal, out int layer)
|
||||||
return shadow;
|
return shadow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vec4 encodeRGBM(vec3 color)
|
vec4 encodeRGBM(vec3 color)
|
||||||
{
|
{
|
||||||
if(dot(color,color)==0)
|
if(dot(color,color)==0)
|
||||||
|
@ -197,9 +231,11 @@ void main()
|
||||||
float NdotL = max(dot(normal, L), 0.0);
|
float NdotL = max(dot(normal, L), 0.0);
|
||||||
vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL;
|
vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL;
|
||||||
|
|
||||||
|
vec3 ambient = ambientLighting(normal, V, F0, albedo, metallic, roughness, 1);
|
||||||
|
|
||||||
int debugLayer;
|
int debugLayer;
|
||||||
float shadow = ShadowCalculation(worldPos, normal, 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));
|
imageStore(gBaseColor, pixelLocation, encodeRGBM(color));
|
||||||
}
|
}
|
|
@ -3,14 +3,30 @@ out vec4 FragColor;
|
||||||
in vec3 WorldPos;
|
in vec3 WorldPos;
|
||||||
|
|
||||||
uniform samplerCube environmentMap;
|
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()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 envColor = texture(environmentMap, WorldPos).rgb;
|
vec3 color = texture(environmentMap, WorldPos).rgb;
|
||||||
|
|
||||||
// HDR tonemap and gamma correct
|
// HDR tonemap
|
||||||
envColor = envColor / (envColor + vec3(1.0));
|
//envColor = envColor / (envColor + vec3(1.0));
|
||||||
envColor = pow(envColor, vec3(1.0/2.2));
|
|
||||||
|
|
||||||
FragColor = vec4(envColor, 1.0);
|
color *= exposure;
|
||||||
|
color = ACESToneMapping(color);
|
||||||
|
|
||||||
|
// gamma correct
|
||||||
|
color = pow(color, vec3(1.0/2.2));
|
||||||
|
|
||||||
|
FragColor = vec4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
#include "IblUtils.h"
|
||||||
|
#include <QOpenGLShaderProgram>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <array>
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
|
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<GLuint, GLuint, GLuint, GLuint> 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<QMatrix4x4, 6> 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<QMatrix4x4, 6>& 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<QMatrix4x4, 6>& 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<QMatrix4x4, 6>& 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<unsigned int>(prefilterMapSize * std::pow(0.5, mip));
|
||||||
|
unsigned int mipHeight = static_cast<unsigned int>(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;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QOpenGLFunctions_4_5_Core>
|
||||||
|
|
||||||
|
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<GLuint, GLuint, GLuint, GLuint> 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<QMatrix4x4, 6>& captureViews);
|
||||||
|
static GLuint generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap);
|
||||||
|
static GLuint generatePrefilterMap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap);
|
||||||
|
static GLuint gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc);
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ using namespace Renderer;
|
||||||
std::vector<BaseStyle> Renderer::ElementStyleFillDemo::toBaseStyles() const
|
std::vector<BaseStyle> Renderer::ElementStyleFillDemo::toBaseStyles() const
|
||||||
{
|
{
|
||||||
return { BaseStyle(std::make_shared<TransformStyle>(),
|
return { BaseStyle(std::make_shared<TransformStyle>(),
|
||||||
std::make_shared<MaterialStyleFill>(std::make_shared<FillPlain>(QColor(0, 255, 0), 0, 0.8))) };
|
std::make_shared<MaterialStyleFill>(std::make_shared<FillPlain>(QColor(202, 148, 44), 1, 0.18))) };
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::ElementStyleStrokeDemo::ElementStyleStrokeDemo(float width)
|
Renderer::ElementStyleStrokeDemo::ElementStyleStrokeDemo(float width)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "PaintingHelper.h"
|
#include "PaintingHelper.h"
|
||||||
using namespace Renderer;
|
using namespace Renderer;
|
||||||
|
|
||||||
PaintingHelper::PaintingHelper(QOpenGLFunctions_4_5_Compatibility* glFunc) :glFunc(glFunc)
|
PaintingHelper::PaintingHelper(QOpenGLFunctions_4_5_Core* glFunc) :glFunc(glFunc)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QVector4D>
|
#include <QVector4D>
|
||||||
#include <QOpenGLFunctions_4_5_Compatibility>
|
#include <QOpenGLFunctions_4_5_Core>
|
||||||
#include "BvhTree.h"
|
#include "BvhTree.h"
|
||||||
#include "Painting.h"
|
#include "Painting.h"
|
||||||
namespace Renderer
|
namespace Renderer
|
||||||
|
@ -11,7 +11,7 @@ namespace Renderer
|
||||||
class PaintingHelper
|
class PaintingHelper
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
QOpenGLFunctions_4_5_Compatibility* glFunc;
|
QOpenGLFunctions_4_5_Core* glFunc;
|
||||||
GLuint paintingOffsetsSSBO, bvhSSBO, bvhBoundSSBO, elementOffsetSSBO, elementIndexSSBO, elementDataSSBO;
|
GLuint paintingOffsetsSSBO, bvhSSBO, bvhBoundSSBO, elementOffsetSSBO, elementIndexSSBO, elementDataSSBO;
|
||||||
std::vector<GLuint> paintingOffsets;
|
std::vector<GLuint> paintingOffsets;
|
||||||
std::vector<GLuint> bvhChildren;
|
std::vector<GLuint> bvhChildren;
|
||||||
|
@ -22,7 +22,7 @@ namespace Renderer
|
||||||
int paintingCount = 0;
|
int paintingCount = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PaintingHelper(QOpenGLFunctions_4_5_Compatibility* glFunc);
|
PaintingHelper(QOpenGLFunctions_4_5_Core* glFunc);
|
||||||
int addPainting(Painting painting);
|
int addPainting(Painting painting);
|
||||||
int addPainting(std::vector<GLuint> bvhChildren, std::vector<QVector4D> bvhBound,
|
int addPainting(std::vector<GLuint> bvhChildren, std::vector<QVector4D> bvhBound,
|
||||||
std::vector<glm::uvec4> elementOffset, std::vector<GLuint> elementIndex, std::vector<GLfloat> elementData);
|
std::vector<glm::uvec4> elementOffset, std::vector<GLuint> elementIndex, std::vector<GLfloat> elementData);
|
||||||
|
|
|
@ -7,12 +7,11 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#include "IblUtils.h"
|
||||||
#include <stb_image.h>
|
|
||||||
|
|
||||||
using namespace Renderer;
|
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 float sunPitch = 105, sunYaw = 80;
|
||||||
static int sunSpeed = 10;
|
static int sunSpeed = 10;
|
||||||
|
|
||||||
|
@ -92,181 +91,24 @@ void RendererGLWidget::setMainLightYaw(float yaw)
|
||||||
//qDebug() << "yaw" << yaw;
|
//qDebug() << "yaw" << yaw;
|
||||||
sunYaw = yaw;
|
sunYaw = yaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::RendererGLWidget::setExposure(float exposure)
|
||||||
|
{
|
||||||
|
this->exposure = exposure;
|
||||||
|
}
|
||||||
|
|
||||||
QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
|
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()
|
void RendererGLWidget::initializeGL()
|
||||||
{
|
{
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
|
||||||
qDebug() << "GL_VERSION" << (char*)glGetString(GL_VERSION);
|
qDebug() << "GL_VERSION" << (char*)glGetString(GL_VERSION);
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glDepthFunc(GL_LEQUAL);
|
glDepthFunc(GL_LEQUAL);
|
||||||
|
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||||
glClearColor(0, 0, 0, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
|
|
||||||
shadowProgramPtr = new QOpenGLShaderProgram;
|
shadowProgramPtr = new QOpenGLShaderProgram;
|
||||||
|
@ -360,6 +202,9 @@ void RendererGLWidget::initializeGL()
|
||||||
shadowMappingProgramPtr->setUniformValue("gPosition", 2);
|
shadowMappingProgramPtr->setUniformValue("gPosition", 2);
|
||||||
shadowMappingProgramPtr->setUniformValue("gMetallicRoughness", 3);
|
shadowMappingProgramPtr->setUniformValue("gMetallicRoughness", 3);
|
||||||
shadowMappingProgramPtr->setUniformValue("gShadowMap", 4);
|
shadowMappingProgramPtr->setUniformValue("gShadowMap", 4);
|
||||||
|
shadowMappingProgramPtr->setUniformValue("irradianceMap", 5);
|
||||||
|
shadowMappingProgramPtr->setUniformValue("prefilterMap", 6);
|
||||||
|
shadowMappingProgramPtr->setUniformValue("brdfLUT", 7);
|
||||||
shadowMappingProgramPtr->release();
|
shadowMappingProgramPtr->release();
|
||||||
|
|
||||||
ssgiProgramPtr->bind();
|
ssgiProgramPtr->bind();
|
||||||
|
@ -372,46 +217,15 @@ void RendererGLWidget::initializeGL()
|
||||||
|
|
||||||
finalProgramPtr->bind();
|
finalProgramPtr->bind();
|
||||||
finalProgramPtr->setUniformValue("gBaseColor", 0);
|
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<QVector3D> rsmSampleCoordsAndWeights;
|
|
||||||
//std::default_random_engine e;
|
|
||||||
//std::uniform_real_distribution<float> 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();
|
finalProgramPtr->release();
|
||||||
|
|
||||||
paintingHelper = new PaintingHelper(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>());
|
paintingHelper = new PaintingHelper(glFunc);
|
||||||
model = new Model(context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
|
model = new Model(context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
|
||||||
|
|
||||||
skyBoxProgramPtr->bind();
|
skyBoxProgramPtr->bind();
|
||||||
skyBoxProgramPtr->setUniformValue("environmentMap", 0);
|
skyBoxProgramPtr->setUniformValue("environmentMap", 0);
|
||||||
skyBoxProgramPtr->release();
|
skyBoxProgramPtr->release();
|
||||||
skyCubemap = generateCubemap(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>());
|
std::tie(skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture) = IblUtils::precomputeCubemaps(glFunc);
|
||||||
|
|
||||||
|
|
||||||
quadVAO.create();
|
quadVAO.create();
|
||||||
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
|
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
|
||||||
|
@ -442,6 +256,8 @@ void RendererGLWidget::initializeGL()
|
||||||
|
|
||||||
void RendererGLWidget::paintGL()
|
void RendererGLWidget::paintGL()
|
||||||
{
|
{
|
||||||
|
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
light.lightDirection.setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
|
light.lightDirection.setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
|
||||||
|
@ -532,7 +348,7 @@ void RendererGLWidget::paintGL()
|
||||||
shadowMappingProgramPtr->setUniformValue("shadowBlendRatio", light.blendRatio);
|
shadowMappingProgramPtr->setUniformValue("shadowBlendRatio", light.blendRatio);
|
||||||
shadowMappingProgramPtr->setUniformValue("camPos", camera.Position);
|
shadowMappingProgramPtr->setUniformValue("camPos", camera.Position);
|
||||||
shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
|
shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
|
||||||
shadowMappingProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);
|
shadowMappingProgramPtr->setUniformValue("mainLightRadiance", mainLightRadiance);
|
||||||
/*glActiveTexture(GL_TEXTURE0);
|
/*glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, gbuffers[0]);*/
|
glBindTexture(GL_TEXTURE_2D, gbuffers[0]);*/
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
@ -543,6 +359,12 @@ void RendererGLWidget::paintGL()
|
||||||
glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
|
glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
|
||||||
glActiveTexture(GL_TEXTURE4);
|
glActiveTexture(GL_TEXTURE4);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
|
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(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);
|
glBindImageTexture(1, gbuffers[8], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F);
|
||||||
glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
|
glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
|
||||||
|
@ -576,25 +398,9 @@ void RendererGLWidget::paintGL()
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
//QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
|
//QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
|
||||||
finalProgramPtr->bind();
|
finalProgramPtr->bind();
|
||||||
/*finalProgramPtr->setUniformValue("camPos", camera.Position);
|
finalProgramPtr->setUniformValue("exposure", exposure);
|
||||||
finalProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
|
|
||||||
finalProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);*/
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, gbuffers[0]);
|
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]);
|
|
||||||
quadVAO.bind();
|
quadVAO.bind();
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
quadVAO.release();
|
quadVAO.release();
|
||||||
|
@ -604,9 +410,10 @@ void RendererGLWidget::paintGL()
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
skyBoxProgramPtr->setUniformValue("view", view);
|
skyBoxProgramPtr->setUniformValue("view", view);
|
||||||
skyBoxProgramPtr->setUniformValue("projection", projection);
|
skyBoxProgramPtr->setUniformValue("projection", projection);
|
||||||
|
skyBoxProgramPtr->setUniformValue("exposure", exposure);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, skyCubemap);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, skyCubemap);
|
||||||
renderCube(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>());
|
IblUtils::renderCube(glFunc);
|
||||||
skyBoxProgramPtr->release();
|
skyBoxProgramPtr->release();
|
||||||
|
|
||||||
GLuint paintingCompDuration;
|
GLuint paintingCompDuration;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
#include <QOpenGLFunctions_4_5_Compatibility>
|
#include <QOpenGLFunctions_4_5_Core>
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
#include <QOpenGLBuffer>
|
#include <QOpenGLBuffer>
|
||||||
#include <QOpenGLVertexArrayObject>
|
#include <QOpenGLVertexArrayObject>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
#include "Painting/PaintingHelper.h"
|
#include "Painting/PaintingHelper.h"
|
||||||
namespace Renderer
|
namespace Renderer
|
||||||
{
|
{
|
||||||
class RendererGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Compatibility
|
class RendererGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -26,6 +26,7 @@ namespace Renderer
|
||||||
void setModel();
|
void setModel();
|
||||||
void setMainLightPitch(float pitch);
|
void setMainLightPitch(float pitch);
|
||||||
void setMainLightYaw(float yaw);
|
void setMainLightYaw(float yaw);
|
||||||
|
void setExposure(float exposure);
|
||||||
protected:
|
protected:
|
||||||
void initializeGL() override;
|
void initializeGL() override;
|
||||||
void paintGL() override;
|
void paintGL() override;
|
||||||
|
@ -47,6 +48,7 @@ namespace Renderer
|
||||||
clock_t lastFrame;
|
clock_t lastFrame;
|
||||||
float deltaTime;
|
float deltaTime;
|
||||||
int shadowMapResolution;
|
int shadowMapResolution;
|
||||||
|
float exposure = 0.8;
|
||||||
|
|
||||||
QOpenGLShaderProgram* shadowProgramPtr = nullptr;
|
QOpenGLShaderProgram* shadowProgramPtr = nullptr;
|
||||||
QOpenGLShaderProgram* modelProgramPtr = nullptr;
|
QOpenGLShaderProgram* modelProgramPtr = nullptr;
|
||||||
|
@ -64,6 +66,9 @@ namespace Renderer
|
||||||
GLuint shadowGbuffer;
|
GLuint shadowGbuffer;
|
||||||
GLuint lightSpaceMatricesUBO;
|
GLuint lightSpaceMatricesUBO;
|
||||||
GLuint skyCubemap;
|
GLuint skyCubemap;
|
||||||
|
GLuint irradianceMap;
|
||||||
|
GLuint prefilterMap;
|
||||||
|
GLuint brdfLUTTexture;
|
||||||
QOpenGLBuffer quadVBO;
|
QOpenGLBuffer quadVBO;
|
||||||
QOpenGLVertexArrayObject quadVAO;
|
QOpenGLVertexArrayObject quadVAO;
|
||||||
Model* model = nullptr;
|
Model* model = nullptr;
|
||||||
|
|
|
@ -9,8 +9,13 @@ RendererWidget::RendererWidget(QWidget *parent)
|
||||||
ui.openGLWidget, &RendererGLWidget::setMainLightPitch);
|
ui.openGLWidget, &RendererGLWidget::setMainLightPitch);
|
||||||
QObject::connect(ui.horizontalSlider_2, &QSlider::valueChanged,
|
QObject::connect(ui.horizontalSlider_2, &QSlider::valueChanged,
|
||||||
ui.openGLWidget, &RendererGLWidget::setMainLightYaw);
|
ui.openGLWidget, &RendererGLWidget::setMainLightYaw);
|
||||||
|
QObject::connect(ui.exposureSlider, &QSlider::valueChanged, [&](int value) {
|
||||||
|
ui.openGLWidget->setExposure(value/100.f);
|
||||||
|
});
|
||||||
|
|
||||||
ui.horizontalSlider->setValue(105);
|
ui.horizontalSlider->setValue(105);
|
||||||
ui.horizontalSlider_2->setValue(80);
|
ui.horizontalSlider_2->setValue(80);
|
||||||
|
ui.exposureSlider->setValue(60);
|
||||||
QObject::connect(ui.openButton, &QPushButton::clicked,
|
QObject::connect(ui.openButton, &QPushButton::clicked,
|
||||||
ui.openGLWidget, &RendererGLWidget::setModel);
|
ui.openGLWidget, &RendererGLWidget::setModel);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue