重构绘制部分

main
wuyize 2024-02-23 23:43:22 +08:00
parent b15ddc0ecb
commit bc118b0a20
21 changed files with 783 additions and 608 deletions

View File

@ -171,6 +171,8 @@
<ClCompile Include="src\Renderer\RendererWidget.cpp" /> <ClCompile Include="src\Renderer\RendererWidget.cpp" />
<ClCompile Include="src\Renderer\Painting\ShortCutTree.cpp" /> <ClCompile Include="src\Renderer\Painting\ShortCutTree.cpp" />
<ClCompile Include="src\Renderer\Painting\StraightLine.cpp" /> <ClCompile Include="src\Renderer\Painting\StraightLine.cpp" />
<ClCompile Include="src\Renderer\RenderPass.cpp" />
<ClCompile Include="src\Renderer\Shader.cpp" />
<ClCompile Include="src\Renderer\VirtualTextureManager.cpp" /> <ClCompile Include="src\Renderer\VirtualTextureManager.cpp" />
<ClCompile Include="src\SvgParser.cpp" /> <ClCompile Include="src\SvgParser.cpp" />
<ClCompile Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.cpp" /> <ClCompile Include="src\Editor\EditorWidgetComponent\StrokeStyleWidget.cpp" />
@ -265,6 +267,8 @@
<ClInclude Include="src\Renderer\Painting\Painting.h" /> <ClInclude Include="src\Renderer\Painting\Painting.h" />
<ClInclude Include="src\Renderer\Preview\ElementRenderer.h" /> <ClInclude Include="src\Renderer\Preview\ElementRenderer.h" />
<ClInclude Include="src\Renderer\Preview\PaintingRenderer.h" /> <ClInclude Include="src\Renderer\Preview\PaintingRenderer.h" />
<ClInclude Include="src\Renderer\RenderPass.h" />
<ClInclude Include="src\Renderer\Shader.h" />
<ClInclude Include="src\Renderer\VirtualTextureManager.h" /> <ClInclude Include="src\Renderer\VirtualTextureManager.h" />
<ClInclude Include="src\SvgParser.h" /> <ClInclude Include="src\SvgParser.h" />
<QtMoc Include="src\NavigationBarWidget.h" /> <QtMoc Include="src\NavigationBarWidget.h" />

View File

@ -303,6 +303,12 @@
<ClCompile Include="src\FlowLayout.cpp"> <ClCompile Include="src\FlowLayout.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\Renderer\RenderPass.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\Renderer\Shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="src\Renderer\RendererGLWidget.h"> <QtMoc Include="src\Renderer\RendererGLWidget.h">
@ -606,6 +612,12 @@
<ClInclude Include="src\FlowLayout.h"> <ClInclude Include="src\FlowLayout.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\Renderer\RenderPass.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\Renderer\Shader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtRcc Include="res\MainWindow.qrc"> <QtRcc Include="res\MainWindow.qrc">

View File

@ -12,7 +12,7 @@ uniform samplerCube irradianceMap;
uniform samplerCube prefilterMap; uniform samplerCube prefilterMap;
uniform sampler2D brdfLUT; 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
{ {
mat4 lightSpaceMatrices[16]; mat4 lightSpaceMatrices[16];

View File

@ -21,6 +21,13 @@ Camera::Camera(float posX, float posY, float posZ, float upX, float upY, float u
updateCameraVectors(); updateCameraVectors();
} }
QMatrix4x4 Camera::GetProjectionMatrix()
{
QMatrix4x4 projection;
projection.perspective(Zoom, Ratio, NearPlane, FarPlane);
return projection;
}
// returns the view matrix calculated using Euler Angles and the LookAt Matrix // returns the view matrix calculated using Euler Angles and the LookAt Matrix
QMatrix4x4 Camera::GetViewMatrix() QMatrix4x4 Camera::GetViewMatrix()
{ {

View File

@ -53,6 +53,8 @@ namespace Renderer
// constructor with scalar values // constructor with scalar values
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch); Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch);
QMatrix4x4 GetProjectionMatrix();
// returns the view matrix calculated using Euler Angles and the LookAt Matrix // returns the view matrix calculated using Euler Angles and the LookAt Matrix
QMatrix4x4 GetViewMatrix(); QMatrix4x4 GetViewMatrix();

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
namespace Renderer namespace Renderer
{ {
class Drawable class Drawable
{ {
public: public:
virtual void draw() = 0; virtual ~Drawable() = default;
virtual void drawShadow() = 0; virtual void draw(QOpenGLShaderProgram* shaderProgram) = 0;
}; virtual void drawShadow(QOpenGLShaderProgram* shadowProgram) = 0;
};
} }

View File

@ -1,3 +1,4 @@
#include <glad/gl.h>
#include "IblUtils.h" #include "IblUtils.h"
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QDebug> #include <QDebug>
@ -9,7 +10,7 @@
#endif #endif
void Renderer::IblUtils::renderCube(QOpenGLFunctions_4_5_Core* glFunc) void Renderer::IblUtils::renderCube(GladGLContext* gl)
{ {
static GLuint cubeVAO = 0, cubeVBO = 0; static GLuint cubeVAO = 0, cubeVBO = 0;
// initialize (if necessary) // initialize (if necessary)
@ -59,39 +60,39 @@ void Renderer::IblUtils::renderCube(QOpenGLFunctions_4_5_Core* glFunc)
-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, 1.0f, // top-left
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f // bottom-left
}; };
glFunc->glGenVertexArrays(1, &cubeVAO); gl->GenVertexArrays(1, &cubeVAO);
glFunc->glGenBuffers(1, &cubeVBO); gl->GenBuffers(1, &cubeVBO);
// fill buffer // fill buffer
glFunc->glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); gl->BindBuffer(GL_ARRAY_BUFFER, cubeVBO);
glFunc->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); gl->BufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// link vertex attributes // link vertex attributes
glFunc->glBindVertexArray(cubeVAO); gl->BindVertexArray(cubeVAO);
glFunc->glEnableVertexAttribArray(0); gl->EnableVertexAttribArray(0);
glFunc->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0); gl->VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glFunc->glEnableVertexAttribArray(1); gl->EnableVertexAttribArray(1);
glFunc->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float))); gl->VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glFunc->glEnableVertexAttribArray(2); gl->EnableVertexAttribArray(2);
glFunc->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); gl->VertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glFunc->glBindBuffer(GL_ARRAY_BUFFER, 0); gl->BindBuffer(GL_ARRAY_BUFFER, 0);
glFunc->glBindVertexArray(0); gl->BindVertexArray(0);
} }
// render Cube // render Cube
glFunc->glBindVertexArray(cubeVAO); gl->BindVertexArray(cubeVAO);
glFunc->glDrawArrays(GL_TRIANGLES, 0, 36); gl->DrawArrays(GL_TRIANGLES, 0, 36);
glFunc->glBindVertexArray(0); gl->BindVertexArray(0);
} }
void Renderer::IblUtils::renderSphere(QOpenGLFunctions_4_5_Core* glFunc) void Renderer::IblUtils::renderSphere(GladGLContext* gl)
{ {
static unsigned int sphereVAO = 0; static unsigned int sphereVAO = 0;
static unsigned int indexCount; static unsigned int indexCount;
if (sphereVAO == 0) if (sphereVAO == 0)
{ {
glFunc->glGenVertexArrays(1, &sphereVAO); gl->GenVertexArrays(1, &sphereVAO);
unsigned int vbo, ebo; unsigned int vbo, ebo;
glFunc->glGenBuffers(1, &vbo); gl->GenBuffers(1, &vbo);
glFunc->glGenBuffers(1, &ebo); gl->GenBuffers(1, &ebo);
std::vector<glm::vec3> positions; std::vector<glm::vec3> positions;
std::vector<glm::vec2> uv; std::vector<glm::vec2> uv;
@ -158,35 +159,35 @@ void Renderer::IblUtils::renderSphere(QOpenGLFunctions_4_5_Core* glFunc)
data.push_back(uv[i].y); data.push_back(uv[i].y);
} }
} }
glFunc->glBindVertexArray(sphereVAO); gl->BindVertexArray(sphereVAO);
glFunc->glBindBuffer(GL_ARRAY_BUFFER, vbo); gl->BindBuffer(GL_ARRAY_BUFFER, vbo);
glFunc->glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW); gl->BufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW);
glFunc->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glFunc->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); gl->BufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
unsigned int stride = (3 + 2 + 3) * sizeof(float); unsigned int stride = (3 + 2 + 3) * sizeof(float);
glFunc->glEnableVertexAttribArray(0); gl->EnableVertexAttribArray(0);
glFunc->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0); gl->VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0);
glFunc->glEnableVertexAttribArray(1); gl->EnableVertexAttribArray(1);
glFunc->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float))); gl->VertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
glFunc->glEnableVertexAttribArray(2); gl->EnableVertexAttribArray(2);
glFunc->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6 * sizeof(float))); gl->VertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6 * sizeof(float)));
} }
glFunc->glBindVertexArray(sphereVAO); gl->BindVertexArray(sphereVAO);
glFunc->glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0); gl->DrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0);
} }
std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc) std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemaps(GladGLContext* gl)
{ {
// pbr: setup framebuffer // pbr: setup framebuffer
// ---------------------- // ----------------------
unsigned int captureFBO; unsigned int captureFBO;
unsigned int captureRBO; unsigned int captureRBO;
glFunc->glCreateFramebuffers(1, &captureFBO); gl->CreateFramebuffers(1, &captureFBO);
glFunc->glCreateRenderbuffers(1, &captureRBO); gl->CreateRenderbuffers(1, &captureRBO);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); gl->BindFramebuffer(GL_FRAMEBUFFER, captureFBO);
glFunc->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
// pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions // pbr: set up projection and view matrices for capturing data onto the 6 cubemap face directions
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
@ -200,14 +201,14 @@ std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemap
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[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)); 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 envCubemap = generateCubemap(gl, captureFBO, captureRBO, captureProjection, captureViews);
GLuint irradianceMap = generateIrradianceMap(glFunc, captureFBO, captureRBO, captureProjection, captureViews, envCubemap); GLuint irradianceMap = generateIrradianceMap(gl, captureFBO, captureRBO, captureProjection, captureViews, envCubemap);
GLuint prefilterMap = generatePrefilterMap(glFunc, captureFBO, captureRBO, captureProjection, captureViews, envCubemap); GLuint prefilterMap = generatePrefilterMap(gl, captureFBO, captureRBO, captureProjection, captureViews, envCubemap);
GLuint brdfLut = gererateBrdfLut(glFunc); GLuint brdfLut = gererateBrdfLut(gl);
return { envCubemap, irradianceMap, prefilterMap, brdfLut }; 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) GLuint Renderer::IblUtils::generateCubemap(GladGLContext* gl, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews)
{ {
// pbr: load the HDR environment map // pbr: load the HDR environment map
// --------------------------------- // ---------------------------------
@ -217,14 +218,14 @@ GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GL
unsigned int hdrTexture = 0; unsigned int hdrTexture = 0;
if (data) if (data)
{ {
glFunc->glGenTextures(1, &hdrTexture); gl->GenTextures(1, &hdrTexture);
glFunc->glBindTexture(GL_TEXTURE_2D, hdrTexture); gl->BindTexture(GL_TEXTURE_2D, hdrTexture);
glFunc->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data); stbi_image_free(data);
} }
@ -234,17 +235,17 @@ GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GL
// pbr: setup cubemap to render to and attach to framebuffer // pbr: setup cubemap to render to and attach to framebuffer
// --------------------------------------------------------- // ---------------------------------------------------------
unsigned int envCubemap; unsigned int envCubemap;
glFunc->glGenTextures(1, &envCubemap); gl->GenTextures(1, &envCubemap);
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
for (unsigned int i = 0; i < 6; ++i) 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); gl->TexImage2D(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); gl->TexParameteri(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); gl->TexParameteri(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); gl->TexParameteri(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); // enable pre-filter mipmap sampling (combatting visible dots artifact) gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // enable pre-filter mipmap sampling (combatting visible dots artifact)
glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// pbr: convert HDR equirectangular environment map to cubemap equivalent // pbr: convert HDR equirectangular environment map to cubemap equivalent
@ -259,52 +260,52 @@ GLuint Renderer::IblUtils::generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GL
shader.bind(); shader.bind();
shader.setUniformValue("equirectangularMap", 0); shader.setUniformValue("equirectangularMap", 0);
shader.setUniformValue("projection", captureProjection); shader.setUniformValue("projection", captureProjection);
glFunc->glActiveTexture(GL_TEXTURE0); gl->ActiveTexture(GL_TEXTURE0);
glFunc->glBindTexture(GL_TEXTURE_2D, hdrTexture); gl->BindTexture(GL_TEXTURE_2D, hdrTexture);
glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); gl->BindRenderbuffer(GL_RENDERBUFFER, captureRBO);
glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cubemapSize, cubemapSize); gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, cubemapSize, cubemapSize);
glFunc->glViewport(0, 0, cubemapSize, cubemapSize); gl->Viewport(0, 0, cubemapSize, cubemapSize);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); gl->BindFramebuffer(GL_FRAMEBUFFER, captureFBO);
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
{ {
shader.setUniformValue("view", captureViews[i]); shader.setUniformValue("view", captureViews[i]);
glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0);
glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderCube(glFunc); renderCube(gl);
} }
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0); gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
// then let OpenGL generate mipmaps from first mip face (combatting visible dots artifact) // then let OpenGL generate mipmaps from first mip face (combatting visible dots artifact)
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
glFunc->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); gl->GenerateMipmap(GL_TEXTURE_CUBE_MAP);
return envCubemap; 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) GLuint Renderer::IblUtils::generateIrradianceMap(GladGLContext* gl, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap)
{ {
// pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale. // pbr: create an irradiance cubemap, and re-scale capture FBO to irradiance scale.
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
unsigned int irradianceMap; unsigned int irradianceMap;
glFunc->glGenTextures(1, &irradianceMap); gl->GenTextures(1, &irradianceMap);
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap);
for (unsigned int i = 0; i < 6; ++i) 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); gl->TexImage2D(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); gl->TexParameteri(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); gl->TexParameteri(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); gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFunc->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); gl->BindFramebuffer(GL_FRAMEBUFFER, captureFBO);
glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); gl->BindRenderbuffer(GL_RENDERBUFFER, captureRBO);
glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, irradianceMapSize, irradianceMapSize); gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, irradianceMapSize, irradianceMapSize);
// pbr: solve diffuse integral by convolution to create an irradiance (cube)map. // pbr: solve diffuse integral by convolution to create an irradiance (cube)map.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -318,41 +319,41 @@ GLuint Renderer::IblUtils::generateIrradianceMap(QOpenGLFunctions_4_5_Core* glFu
irradianceShader.bind(); irradianceShader.bind();
irradianceShader.setUniformValue("environmentMap", 0); irradianceShader.setUniformValue("environmentMap", 0);
irradianceShader.setUniformValue("projection", captureProjection); irradianceShader.setUniformValue("projection", captureProjection);
glFunc->glActiveTexture(GL_TEXTURE0); gl->ActiveTexture(GL_TEXTURE0);
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
glFunc->glViewport(0, 0, irradianceMapSize, irradianceMapSize); // don't forget to configure the viewport to the capture dimensions. gl->Viewport(0, 0, irradianceMapSize, irradianceMapSize); // don't forget to configure the viewport to the capture dimensions.
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); gl->BindFramebuffer(GL_FRAMEBUFFER, captureFBO);
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
{ {
irradianceShader.setUniformValue("view", captureViews[i]); irradianceShader.setUniformValue("view", captureViews[i]);
glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0);
glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderCube(glFunc); renderCube(gl);
} }
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0); gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
return irradianceMap; 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) GLuint Renderer::IblUtils::generatePrefilterMap(GladGLContext* gl, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap)
{ {
// pbr: create a pre-filter cubemap, and re-scale capture FBO to pre-filter scale. // pbr: create a pre-filter cubemap, and re-scale capture FBO to pre-filter scale.
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
unsigned int prefilterMap; unsigned int prefilterMap;
glFunc->glGenTextures(1, &prefilterMap); gl->GenTextures(1, &prefilterMap);
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap);
for (unsigned int i = 0; i < 6; ++i) 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); gl->TexImage2D(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); gl->TexParameteri(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); gl->TexParameteri(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); gl->TexParameteri(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 gl->TexParameteri(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); gl->TexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// generate mipmaps for the cubemap so OpenGL automatically allocates the required memory. // generate mipmaps for the cubemap so OpenGL automatically allocates the required memory.
glFunc->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); gl->GenerateMipmap(GL_TEXTURE_CUBE_MAP);
// pbr: run a quasi monte-carlo simulation on the environment lighting to create a prefilter (cube)map. // pbr: run a quasi monte-carlo simulation on the environment lighting to create a prefilter (cube)map.
// ---------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------
@ -366,52 +367,52 @@ GLuint Renderer::IblUtils::generatePrefilterMap(QOpenGLFunctions_4_5_Core* glFun
prefilterShader.bind(); prefilterShader.bind();
prefilterShader.setUniformValue("environmentMap", 0); prefilterShader.setUniformValue("environmentMap", 0);
prefilterShader.setUniformValue("projection", captureProjection); prefilterShader.setUniformValue("projection", captureProjection);
glFunc->glActiveTexture(GL_TEXTURE0); gl->ActiveTexture(GL_TEXTURE0);
glFunc->glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); gl->BindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); gl->BindFramebuffer(GL_FRAMEBUFFER, captureFBO);
unsigned int maxMipLevels = 5; unsigned int maxMipLevels = 5;
for (unsigned int mip = 0; mip < maxMipLevels; ++mip) for (unsigned int mip = 0; mip < maxMipLevels; ++mip)
{ {
// reisze framebuffer according to mip-level size. // reisze framebuffer according to mip-level size.
unsigned int mipWidth = static_cast<unsigned int>(prefilterMapSize * std::pow(0.5, mip)); 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)); unsigned int mipHeight = static_cast<unsigned int>(prefilterMapSize * std::pow(0.5, mip));
glFunc->glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); gl->BindRenderbuffer(GL_RENDERBUFFER, captureRBO);
glFunc->glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight); gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
glFunc->glViewport(0, 0, mipWidth, mipHeight); gl->Viewport(0, 0, mipWidth, mipHeight);
float roughness = (float)mip / (float)(maxMipLevels - 1); float roughness = (float)mip / (float)(maxMipLevels - 1);
prefilterShader.setUniformValue("roughness", roughness); prefilterShader.setUniformValue("roughness", roughness);
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
{ {
prefilterShader.setUniformValue("view", captureViews[i]); prefilterShader.setUniformValue("view", captureViews[i]);
glFunc->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip);
glFunc->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderCube(glFunc); renderCube(gl);
} }
} }
glFunc->glBindFramebuffer(GL_FRAMEBUFFER, 0); gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
return prefilterMap; return prefilterMap;
} }
GLuint Renderer::IblUtils::gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc) GLuint Renderer::IblUtils::gererateBrdfLut(GladGLContext* gl)
{ {
constexpr int lutSize = 512; constexpr int lutSize = 512;
// pbr: generate a 2D LUT from the BRDF equations used. // pbr: generate a 2D LUT from the BRDF equations used.
// ---------------------------------------------------- // ----------------------------------------------------
unsigned int brdfLUTTexture; unsigned int brdfLUTTexture;
glFunc->glGenTextures(1, &brdfLUTTexture); gl->GenTextures(1, &brdfLUTTexture);
// pre-allocate enough memory for the LUT texture. // pre-allocate enough memory for the LUT texture.
glFunc->glBindTexture(GL_TEXTURE_2D, brdfLUTTexture); gl->BindTexture(GL_TEXTURE_2D, brdfLUTTexture);
glFunc->glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, lutSize, lutSize, 0, GL_RG, GL_FLOAT, 0); gl->TexImage2D(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 // be sure to set wrapping mode to GL_CLAMP_TO_EDGE
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFunc->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
QOpenGLShaderProgram brdfShader; QOpenGLShaderProgram brdfShader;
if (!brdfShader.addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/brdf_lut.comp")) if (!brdfShader.addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/brdf_lut.comp"))
@ -419,8 +420,8 @@ GLuint Renderer::IblUtils::gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc)
if (!brdfShader.link()) if (!brdfShader.link())
qDebug() << "ERROR:" << brdfShader.log(); qDebug() << "ERROR:" << brdfShader.log();
brdfShader.bind(); brdfShader.bind();
glFunc->glBindImageTexture(0, brdfLUTTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RG16F); gl->BindImageTexture(0, brdfLUTTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RG16F);
glFunc->glDispatchCompute(ceil(lutSize / 8.), ceil(lutSize / 8.), 1); gl->DispatchCompute(ceil(lutSize / 8.), ceil(lutSize / 8.), 1);
brdfShader.release(); brdfShader.release();
return brdfLUTTexture; return brdfLUTTexture;
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <QOpenGLFunctions_4_5_Core> #include <QOpenGLFunctions_4_5_Core>
struct GladGLContext;
namespace Renderer namespace Renderer
{ {
class IblUtils class IblUtils
@ -9,20 +9,20 @@ namespace Renderer
static constexpr int cubemapSize = 1024; static constexpr int cubemapSize = 1024;
static constexpr int irradianceMapSize = 32; static constexpr int irradianceMapSize = 32;
static constexpr int prefilterMapSize = 128; static constexpr int prefilterMapSize = 128;
static void renderCube(QOpenGLFunctions_4_5_Core* glFunc); static void renderCube(GladGLContext* gl);
static void renderSphere(QOpenGLFunctions_4_5_Core* glFunc); static void renderSphere(GladGLContext* gl);
/** /**
* @brief * @brief
* @return GLuint envCubemap * @return GLuint envCubemap
* @return GLuint irradianceMap * @return GLuint irradianceMap
* @return GLuint prefilterMap * @return GLuint prefilterMap
* @return GLuint brdfLut * @return GLuint brdfLut
*/ */
static std::tuple<GLuint, GLuint, GLuint, GLuint> precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc); static std::tuple<GLuint, GLuint, GLuint, GLuint> precomputeCubemaps(GladGLContext* gl);
private: private:
static GLuint generateCubemap(QOpenGLFunctions_4_5_Core* glFunc, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews); static GLuint generateCubemap(GladGLContext* gl, 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 generateIrradianceMap(GladGLContext* gl, 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 generatePrefilterMap(GladGLContext* gl, GLuint captureFBO, GLuint captureRBO, const QMatrix4x4& captureProjection, const std::array<QMatrix4x4, 6>& captureViews, GLuint envCubemap);
static GLuint gererateBrdfLut(QOpenGLFunctions_4_5_Core* glFunc); static GLuint gererateBrdfLut(GladGLContext* gl);
}; };
} }

View File

@ -11,23 +11,24 @@
namespace Renderer namespace Renderer
{ {
class Light class Light
{ {
public: public:
QVector3D lightDirection = QVector3D(0.2, 4, 1).normalized(); QVector3D lightDirection = QVector3D(0.2, 4, 1).normalized();
std::vector<float> shadowCascadeLevels; QVector3D radiance = QVector3D(0, 0, 0);
float blendRatio = 0.3; std::vector<float> shadowCascadeLevels;
std::vector<float> frustumSizes; float blendRatio = 0.3;
Model* model = nullptr; std::vector<float> frustumSizes;
Light(Camera* camera); Model* model = nullptr;
void updateShadowCascadeLevels(); Light(Camera* camera);
std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& projview); void updateShadowCascadeLevels();
std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& proj, const QMatrix4x4& view); std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& projview);
QMatrix4x4 getLightSpaceMatrix(const float nearPlane, const float farPlane); std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& proj, const QMatrix4x4& view);
std::vector<QMatrix4x4> getLightSpaceMatrices(); QMatrix4x4 getLightSpaceMatrix(const float nearPlane, const float farPlane);
private: std::vector<QMatrix4x4> getLightSpaceMatrices();
Camera* camera; private:
Camera* camera;
}; };
} }

View File

@ -9,16 +9,14 @@ Renderer::Vertex::Vertex(const aiVector3D& position, const aiVector3D& normal, c
{ {
} }
Mesh::Mesh(QOpenGLFunctions_4_5_Core* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model) Mesh::Mesh(QOpenGLFunctions_4_5_Core* glFunc, const QMatrix4x4& model)
: glFunc(glFunc) : glFunc(glFunc)
, shaderProgram(shaderProgram)
, shadowProgram(shadowProgram)
, VBO(QOpenGLBuffer::VertexBuffer) , VBO(QOpenGLBuffer::VertexBuffer)
, EBO(QOpenGLBuffer::IndexBuffer) , EBO(QOpenGLBuffer::IndexBuffer)
, model(model) , model(model)
{ {
} }
void Mesh::draw() void Mesh::draw(QOpenGLShaderProgram* shaderProgram)
{ {
if (shaderProgram->bind()) if (shaderProgram->bind())
{ {
@ -43,7 +41,7 @@ void Mesh::draw()
shaderProgram->release(); shaderProgram->release();
} }
} }
void Mesh::drawShadow() void Mesh::drawShadow(QOpenGLShaderProgram* shadowProgram)
{ {
if (shadowProgram->bind()) if (shadowProgram->bind())
{ {
@ -72,16 +70,17 @@ void Mesh::setupMesh()
EBO.bind(); EBO.bind();
EBO.allocate(indices.data(), indices.size() * sizeof(unsigned int)); EBO.allocate(indices.data(), indices.size() * sizeof(unsigned int));
if (shaderProgram->bind()) enum VertexAttribute : GLuint {
{ kPosition = 0, kNormal = 1, kTexCoords = 2
shaderProgram->enableAttributeArray(0); };
shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(Vertex));
shaderProgram->enableAttributeArray(1); glFunc->glEnableVertexAttribArray(kPosition);
shaderProgram->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, Normal), 3, sizeof(Vertex)); glFunc->glVertexAttribPointer(kPosition, sizeof(Vertex::Position) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
shaderProgram->enableAttributeArray(2); glFunc->glEnableVertexAttribArray(kNormal);
shaderProgram->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, TexCoords), 2, sizeof(Vertex)); glFunc->glVertexAttribPointer(kNormal, sizeof(Vertex::Normal) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
shaderProgram->release(); glFunc->glEnableVertexAttribArray(kTexCoords);
} glFunc->glVertexAttribPointer(kTexCoords, sizeof(Vertex::TexCoords) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
VAO.release(); VAO.release();
} }

View File

@ -48,11 +48,10 @@ namespace Renderer
QMatrix4x4 model; QMatrix4x4 model;
QOpenGLFunctions_4_5_Core* glFunc; QOpenGLFunctions_4_5_Core* glFunc;
QOpenGLShaderProgram* shaderProgram, * shadowProgram;
Mesh(QOpenGLFunctions_4_5_Core* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model); Mesh(QOpenGLFunctions_4_5_Core* glFunc, const QMatrix4x4& model);
void draw() override; void draw(QOpenGLShaderProgram* shaderProgram) override;
void drawShadow() override; void drawShadow(QOpenGLShaderProgram* shadowProgram) override;
void setupMesh(); void setupMesh();
private: private:

View File

@ -21,27 +21,28 @@
using namespace Renderer; using namespace Renderer;
using std::vector; using std::vector;
Model::Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, Model::Model(QOpenGLContext* context, VirtualTextureManager* vtManager)
QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager)
: context(context) : context(context)
, glFunc(context->versionFunctions<QOpenGLFunctions_4_5_Core>()) , glFunc(context->versionFunctions<QOpenGLFunctions_4_5_Core>())
, shaderProgram(shaderProgram)
, paintingProgram(paintingProgram)
, shadowProgram(shadowProgram)
, vtManager(vtManager) , vtManager(vtManager)
{ {
} }
void Model::draw() {
for (auto& mesh : meshes) { void Model::draw(QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram)
mesh->draw(); {
} for (auto& mesh : meshes)
mesh->draw(shaderProgram);
for (auto& mesh : paintingMeshes)
mesh->draw(paintingProgram);
} }
void Model::drawShadow() { void Model::drawShadow(QOpenGLShaderProgram* shadowProgram)
for (auto& mesh : meshes) { {
mesh->drawShadow(); for (auto& mesh : meshes)
} mesh->drawShadow(shadowProgram);
for (auto& mesh : paintingMeshes)
mesh->drawShadow(shadowProgram);
} }
void Renderer::Model::loadModel(QString path) void Renderer::Model::loadModel(QString path)
@ -121,19 +122,14 @@ void Model::processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4)
{ {
// 处理节点所有的网格(如果有的话) // 处理节点所有的网格(如果有的话)
for (unsigned int i = 0; i < node->mNumMeshes; i++) for (unsigned int i = 0; i < node->mNumMeshes; i++)
{ processMesh(scene->mMeshes[node->mMeshes[i]], scene, mat4);
if (auto mesh = processMesh(scene->mMeshes[node->mMeshes[i]], scene, mat4))
meshes.emplace_back(std::move(mesh));
}
// 接下来对它的子节点重复这一过程 // 接下来对它的子节点重复这一过程
for (unsigned int i = 0; i < node->mNumChildren; i++) for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene, mat4 * node->mChildren[i]->mTransformation); processNode(node->mChildren[i], scene, mat4 * node->mChildren[i]->mTransformation);
}
} }
std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model) void Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model)
{ {
QMatrix4x4 modelQ((float*)&model); QMatrix4x4 modelQ((float*)&model);
@ -157,7 +153,7 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
indices.insert(indices.end(), face->mIndices, face->mIndices + face->mNumIndices); indices.insert(indices.end(), face->mIndices, face->mIndices + face->mNumIndices);
if (vertices.empty() || indices.empty()) if (vertices.empty() || indices.empty())
return nullptr; return;
aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex];
@ -165,11 +161,11 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
aiString str; aiString str;
material->GetTexture(aiTextureType_BASE_COLOR, 0, &str); material->GetTexture(aiTextureType_BASE_COLOR, 0, &str);
return std::string(str.C_Str()); return std::string(str.C_Str());
}()); paintingProgram != nullptr && iter != paintingMap.end()) }()); iter != paintingMap.end())
{ {
qDebug() << iter->first.c_str() << "Replaced"; qDebug() << iter->first.c_str() << "Replaced";
auto mesh = std::make_unique<PaintingMesh>(glFunc, paintingProgram, shadowProgram, modelQ); auto& mesh = paintingMeshes.emplace_back(std::make_unique<PaintingMesh>(glFunc, modelQ));
auto& [paintingPath, leftBottom, rightTop] = iter->second; auto& [paintingPath, leftBottom, rightTop] = iter->second;
auto [paintingId, ratio] = loadPainting(paintingPath); auto [paintingId, ratio] = loadPainting(paintingPath);
@ -188,11 +184,10 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
mesh->indices = indices; mesh->indices = indices;
mesh->setupMesh(); mesh->setupMesh();
return mesh;
} }
else else
{ {
auto mesh = std::make_unique<Mesh>(glFunc, shaderProgram, shadowProgram, modelQ); auto& mesh = meshes.emplace_back(std::make_unique<Mesh>(glFunc, modelQ));
mesh->vertices = vertices; mesh->vertices = vertices;
mesh->indices = indices; mesh->indices = indices;
@ -214,7 +209,6 @@ std::unique_ptr<Drawable> Model::processMesh(aiMesh* mesh, const aiScene* scene,
} }
mesh->setupMesh(); mesh->setupMesh();
return mesh;
} }
} }

View File

@ -4,15 +4,16 @@
#include "VirtualTextureManager.h" #include "VirtualTextureManager.h"
#include <QDir> #include <QDir>
#include <assimp/scene.h> #include <assimp/scene.h>
#include "PaintingMesh.h"
namespace Renderer namespace Renderer
{ {
class Model class Model
{ {
public: public:
Model(QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, VirtualTextureManager* vtManager); Model(QOpenGLContext* context, VirtualTextureManager* vtManager);
void draw(); void draw(QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram);
void drawShadow(); void drawShadow(QOpenGLShaderProgram* shadowProgram);
void loadModel(QString path); void loadModel(QString path);
void unloadModel(); void unloadModel();
const std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>>& getPaintingMap(); const std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>>& getPaintingMap();
@ -24,9 +25,6 @@ namespace Renderer
private: private:
QOpenGLContext* context = nullptr; QOpenGLContext* context = nullptr;
QOpenGLFunctions_4_5_Core* glFunc = nullptr; QOpenGLFunctions_4_5_Core* glFunc = nullptr;
QOpenGLShaderProgram* shaderProgram = nullptr;
QOpenGLShaderProgram* paintingProgram = nullptr;
QOpenGLShaderProgram* shadowProgram = nullptr;
VirtualTextureManager* vtManager = nullptr; VirtualTextureManager* vtManager = nullptr;
/** /**
@ -36,17 +34,18 @@ namespace Renderer
std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>> paintingMap; std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>> paintingMap;
std::unordered_map<std::string, std::pair<GLuint, float>> paintingLoaded; std::unordered_map<std::string, std::pair<GLuint, float>> paintingLoaded;
std::unordered_map<std::string, QOpenGLTexture> texturesLoaded; std::unordered_map<std::string, QOpenGLTexture> texturesLoaded;
std::vector<std::unique_ptr<Drawable>> meshes; std::vector<std::unique_ptr<Mesh>> meshes;
std::vector<std::unique_ptr<PaintingMesh>> paintingMeshes;
QDir directory; /// 模型所在路径 QDir directory; /// 模型所在路径
QString name; /// 模型文件名 QString name; /// 模型文件名
/// 递归遍历结点 /// 递归遍历结点
void processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4 = aiMatrix4x4()); void processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4 = aiMatrix4x4());
/// 加载网格 /// 加载网格
std::unique_ptr<Drawable> processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model); void processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 model);
/// 加载材质纹理 /// 加载材质纹理
GLuint loadMaterialTextures(aiMaterial* mat, aiTextureType type); GLuint loadMaterialTextures(aiMaterial* mat, aiTextureType type);

View File

@ -1,15 +1,13 @@
#include "PaintingMesh.h" #include "PaintingMesh.h"
using namespace Renderer; using namespace Renderer;
PaintingMesh::PaintingMesh(QOpenGLFunctions_4_5_Core* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model) PaintingMesh::PaintingMesh(QOpenGLFunctions_4_5_Core* glFunc, const QMatrix4x4& model)
: glFunc(glFunc) : glFunc(glFunc)
, shaderProgram(shaderProgram)
, shadowProgram(shadowProgram)
, VBO(QOpenGLBuffer::VertexBuffer) , VBO(QOpenGLBuffer::VertexBuffer)
, EBO(QOpenGLBuffer::IndexBuffer) , EBO(QOpenGLBuffer::IndexBuffer)
, model(model) , model(model)
{ {
} }
void PaintingMesh::draw() void PaintingMesh::draw(QOpenGLShaderProgram* shaderProgram)
{ {
if (shaderProgram->bind()) if (shaderProgram->bind())
{ {
@ -26,7 +24,7 @@ void PaintingMesh::draw()
shaderProgram->release(); shaderProgram->release();
} }
} }
void PaintingMesh::drawShadow() void PaintingMesh::drawShadow(QOpenGLShaderProgram* shadowProgram)
{ {
if (shadowProgram->bind()) if (shadowProgram->bind())
{ {
@ -54,16 +52,17 @@ void PaintingMesh::setupMesh()
EBO.bind(); EBO.bind();
EBO.allocate(indices.data(), indices.size() * sizeof(unsigned int)); EBO.allocate(indices.data(), indices.size() * sizeof(unsigned int));
if (shaderProgram->bind()) enum VertexAttribute : GLuint {
{ kPosition = 0, kNormal = 1, kTexCoords = 2
shaderProgram->enableAttributeArray(0); };
shaderProgram->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(Vertex));
shaderProgram->enableAttributeArray(1); glFunc->glEnableVertexAttribArray(kPosition);
shaderProgram->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, Normal), 3, sizeof(Vertex)); glFunc->glVertexAttribPointer(kPosition, sizeof(Vertex::Position) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
shaderProgram->enableAttributeArray(2); glFunc->glEnableVertexAttribArray(kNormal);
shaderProgram->setAttributeBuffer(2, GL_FLOAT, offsetof(Vertex, TexCoords), 2, sizeof(Vertex)); glFunc->glVertexAttribPointer(kNormal, sizeof(Vertex::Normal) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
shaderProgram->release(); glFunc->glEnableVertexAttribArray(kTexCoords);
} glFunc->glVertexAttribPointer(kTexCoords, sizeof(Vertex::TexCoords) / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
VAO.release(); VAO.release();
} }

View File

@ -24,12 +24,11 @@ namespace Renderer
GLuint textureMetallicRoughness; GLuint textureMetallicRoughness;
QMatrix4x4 model; QMatrix4x4 model;
QOpenGLFunctions_4_5_Core* glFunc; QOpenGLFunctions_4_5_Core* glFunc;
QOpenGLShaderProgram* shaderProgram, * shadowProgram;
GLuint paintingId; GLuint paintingId;
PaintingMesh(QOpenGLFunctions_4_5_Core* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, const QMatrix4x4& model); PaintingMesh(QOpenGLFunctions_4_5_Core* glFunc, const QMatrix4x4& model);
void draw() override; void draw(QOpenGLShaderProgram* shaderProgram) override;
void drawShadow() override; void drawShadow(QOpenGLShaderProgram* shadowProgram) override;
void setupMesh(); void setupMesh();
private: private:

View File

@ -0,0 +1,261 @@
#include <glad/gl.h>
#include "RenderPass.h"
#include "IblUtils.h"
namespace Renderer
{
ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, Light& light, Model*& model)
: RenderPass(gl)
, modelShadowShader(":/Shaders/model_shadow.vert", ":/Shaders/model_shadow.frag", ":/Shaders/model_shadow.geom")
, shadowFboHandle(shadowFboHandle), shadowMapResolution(shadowMapResolution), light(light), model(model)
{
modelShadowShader.bind();
gl->GenBuffers(1, &lightSpaceMatricesUBO);
gl->BindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO);
gl->BufferData(GL_UNIFORM_BUFFER, sizeof(QMatrix4x4) * 16, nullptr, GL_STATIC_DRAW);
gl->BindBufferBase(GL_UNIFORM_BUFFER, 0, lightSpaceMatricesUBO);
gl->BindBuffer(GL_UNIFORM_BUFFER, 0);
modelShadowShader.release();
}
void ShadowMapPass::dispatch()
{
const std::vector<QMatrix4x4> lightMatrices = light.getLightSpaceMatrices();
gl->BindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO);
for (size_t i = 0; i < lightMatrices.size(); i++)
{
gl->BufferSubData(GL_UNIFORM_BUFFER, i * 16 * sizeof(GLfloat), 16 * sizeof(GLfloat), lightMatrices[i].data());
}
gl->BindBuffer(GL_UNIFORM_BUFFER, 0);
gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution);
gl->Clear(GL_DEPTH_BUFFER_BIT);
//gl->CullFace(GL_FRONT);
if (model != nullptr)
model->drawShadow(&modelShadowShader);
//gl->CullFace(GL_BACK);
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
}
GeometryPass::GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, QOpenGLFramebufferObject*& fbo, Model*& model, QMatrix4x4& projection, QMatrix4x4& view)
: RenderPass(gl)
, modelShader(":/Shaders/model.vert", ":/Shaders/model.frag")
, paintingShader(":/Shaders/painting.vert", ":/Shaders/painting.frag")
, plainShader(":/Shaders/shader.vert", ":/Shaders/shader.frag")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, fbo(fbo)
, model(model)
, projection(projection)
, view(view)
{
}
void GeometryPass::dispatch()
{
if (fbo->bind())
{
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl->Viewport(0, 0, frameWidth, frameHeight);
modelShader.bind();
modelShader.setUniformValue("projection", projection);
modelShader.setUniformValue("view", view);
modelShader.release();
paintingShader.bind();
paintingShader.setUniformValue("projection", projection);
paintingShader.setUniformValue("view", view);
paintingShader.release();
if (model != nullptr)
model->draw(&modelShader, &paintingShader);
/// Debug Lighting
if (false)
{
plainShader.bind();
plainShader.setUniformValue("projection", projection);
plainShader.setUniformValue("view", view);
plainShader.setUniformValue("albedo", 0.5f, 0.5f, 0.5f);
QMatrix4x4 model;
int nrRows = 7, nrColumns = 7;
float spacing = 2.5;
for (int row = 0; row < nrRows; ++row)
{
plainShader.setUniformValue("metallic", (float)row / (float)nrRows);
for (int col = 0; col < nrColumns; ++col)
{
plainShader.setUniformValue("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f));
model.setToIdentity();
model.scale(10);
model.translate(QVector3D((float)(col - (nrColumns / 2)) * spacing,
(float)(row - (nrRows / 2)) * spacing + 20,
-2.0f));
plainShader.setUniformValue("model", model);
IblUtils::renderSphere(gl);
}
}
plainShader.release();
}
fbo->release();
}
}
PageIDCallbackPass::PageIDCallbackPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, QOpenGLFramebufferObject*& fbo, GLuint* gBuffers, GLuint& gPageID, VirtualTextureManager& vtManager)
: RenderPass(gl)
, pageIdDownsampleShader(":/Shaders/pageId_downsample.comp")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, fbo(fbo)
, gBuffers(gBuffers)
, gPageID(gPageID)
, vtManager(vtManager)
{
}
void PageIDCallbackPass::dispatch()
{
if (fbo->bind())
{
pageIdDownsampleShader.bind();
gl->BindImageTexture(3, gPageID, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16UI);
gl->Uniform2ui(0, rand() % 8, rand() % 8);
gl->DispatchCompute(ceil(frameWidth / 8. / 8.), ceil(frameWidth / 8. / 8.), 1);
pageIdDownsampleShader.release();
std::vector<glm::u16vec2> pixels;
pixels.resize(ceil(frameWidth / 8.) * ceil(frameHeight / 8.));
//fboPtr->bind();
gl->ReadBuffer(GL_COLOR_ATTACHMENT0 + (&gPageID - gBuffers));
gl->ReadnPixels(0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
//gl->GetTextureSubImage(gbuffers[4], 0, 0, 0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1, GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
vtManager.tryUpdatePages(pixels);
fbo->release();
}
}
LightingPass::LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, QMatrix4x4& view, Camera& camera, Light& light, GLuint& gBaseColor, GLuint& gNormal, GLuint& gPosition, GLuint& gMetallicRoughness, GLuint& shadowGbuffer, GLuint& irradianceMap, GLuint& prefilterMap, GLuint& brdfLUTTexture)
: RenderPass(gl)
, pbrShader(":/Shaders/shadow_mapping.comp")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, view(view)
, camera(camera)
, light(light)
, gBaseColor(gBaseColor), gNormal(gNormal), gPosition(gPosition), gMetallicRoughness(gMetallicRoughness)
, shadowGbuffer(shadowGbuffer)
, irradianceMap(irradianceMap)
, prefilterMap(prefilterMap)
, brdfLUTTexture(brdfLUTTexture)
{
pbrShader.bind();
pbrShader.setUniformValue("gNormal", gNormalBinding);
pbrShader.setUniformValue("gPosition", gPositionBinding);
pbrShader.setUniformValue("gMetallicRoughness", gMetallicRoughnessBinding);
pbrShader.setUniformValue("gShadowMap", gShadowMapBinding);
pbrShader.setUniformValue("irradianceMap", irradianceMapBinding);
pbrShader.setUniformValue("prefilterMap", prefilterMapBinding);
pbrShader.setUniformValue("brdfLUT", brdfLUTBinding);
pbrShader.release();
}
void LightingPass::dispatch()
{
pbrShader.bind();
pbrShader.setUniformValue("view", view);
pbrShader.setUniformValue("farPlane", camera.FarPlane);
pbrShader.setUniformValueArray("shadowCascadePlaneDistances", light.shadowCascadeLevels.data(), light.shadowCascadeLevels.size(), 1);
pbrShader.setUniformValueArray("shadowBiases", light.frustumSizes.data(), light.frustumSizes.size(), 1);
pbrShader.setUniformValue("shadowCascadeCount", (GLint)light.shadowCascadeLevels.size());
pbrShader.setUniformValue("shadowBlendRatio", light.blendRatio);
pbrShader.setUniformValue("camPos", camera.Position);
pbrShader.setUniformValue("mainLightDirection", light.lightDirection);
pbrShader.setUniformValue("mainLightRadiance", light.radiance);
gl->BindTextureUnit(gNormalBinding, gNormal);
gl->BindTextureUnit(gPositionBinding, gPosition);
gl->BindTextureUnit(gMetallicRoughnessBinding, gMetallicRoughness);
gl->BindTextureUnit(gShadowMapBinding, shadowGbuffer);
gl->BindTextureUnit(irradianceMapBinding, irradianceMap);
gl->BindTextureUnit(prefilterMapBinding, prefilterMap);
gl->BindTextureUnit(brdfLUTBinding, brdfLUTTexture);
gl->BindImageTexture(0, gBaseColor, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
pbrShader.release();
}
FinalPass::FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure)
: RenderPass(gl)
, finalShader(":Shaders/final.vert", ":Shaders/final.frag")
, frameWidth(frameWidth)
, frameHeight(frameHeight)
, gBaseColor(gBaseColor)
, exposure(exposure)
{
finalShader.bind();
finalShader.setUniformValue("gBaseColor", gBaseColorBinding);
finalShader.release();
quadVAO.create();
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
quadVBO.create();
quadVBO.bind();
GLfloat vertex[] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
quadVBO.allocate(vertex, sizeof(vertex));
quadVBO.bind();
gl->EnableVertexAttribArray(0);
gl->VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
nullptr);
gl->EnableVertexAttribArray(1);
gl->VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
reinterpret_cast<void*>(3 * sizeof(GLfloat)));
quadVBO.release();
}
void FinalPass::dispatch()
{
gl->Viewport(0, 0, frameWidth, frameHeight);
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
finalShader.bind();
finalShader.setUniformValue("exposure", exposure);
gl->BindTextureUnit(gBaseColorBinding, gBaseColor);
quadVAO.bind();
gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
quadVAO.release();
finalShader.release();
}
SkyboxPass::SkyboxPass(GladGLContext* gl, QMatrix4x4& projection, QMatrix4x4& view, float& exposure, GLuint& skyCubemap)
: RenderPass(gl)
, skyBoxShader(":Shaders/skybox.vert", ":Shaders/skybox.frag")
, projection(projection)
, view(view)
, exposure(exposure)
, skyCubemap(skyCubemap)
{
skyBoxShader.bind();
skyBoxShader.setUniformValue("environmentMap", environmentMapBinding);
skyBoxShader.release();
}
void SkyboxPass::dispatch()
{
skyBoxShader.bind();
gl->Disable(GL_CULL_FACE);
skyBoxShader.setUniformValue("view", view);
skyBoxShader.setUniformValue("projection", projection);
skyBoxShader.setUniformValue("exposure", exposure);
gl->BindTextureUnit(environmentMapBinding, skyCubemap);
IblUtils::renderCube(gl);
skyBoxShader.release();
}
}

View File

@ -0,0 +1,132 @@
#pragma once
#include "Shader.h"
#include "Model.h"
#include "Light.h"
#include <QOpenGLFramebufferObject>
struct GladGLContext;
namespace Renderer
{
class RenderPass
{
public:
RenderPass(GladGLContext* gl) : gl(gl) {};
virtual ~RenderPass() = default;
virtual void dispatch() = 0;
protected:
GladGLContext* gl = nullptr;
};
class ShadowMapPass : public RenderPass
{
public:
ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, Light& light, Model*& model);
void dispatch();
private:
Shader modelShadowShader;
GLuint& shadowFboHandle;
int& shadowMapResolution;
Light& light;
Model*& model;
GLuint lightSpaceMatricesUBO;
};
class GeometryPass : public RenderPass
{
public:
GeometryPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight,
QOpenGLFramebufferObject*& fbo, Model*& model, QMatrix4x4& projection, QMatrix4x4& view);
void dispatch();
private:
Shader modelShader, paintingShader, plainShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
QOpenGLFramebufferObject*& fbo;
Model*& model;
QMatrix4x4& projection;
QMatrix4x4& view;
};
class PageIDCallbackPass : public RenderPass
{
public:
PageIDCallbackPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, QOpenGLFramebufferObject*& fbo,
GLuint* gBuffers, GLuint& gPageID, VirtualTextureManager& vtManager);
void dispatch();
private:
Shader pageIdDownsampleShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
QOpenGLFramebufferObject*& fbo;
GLuint* gBuffers;
GLuint& gPageID;
VirtualTextureManager& vtManager;
};
class LightingPass : public RenderPass
{
public:
LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight,
QMatrix4x4& view, Camera& camera, Light& light,
GLuint& gBaseColor, GLuint& gNormal, GLuint& gPosition, GLuint& gMetallicRoughness,
GLuint& shadowGbuffer, GLuint& irradianceMap, GLuint& prefilterMap, GLuint& brdfLUTTexture);
void dispatch();
private:
Shader pbrShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
QMatrix4x4& view;
Camera& camera;
Light& light;
GLuint& gBaseColor;
GLuint& gNormal;
GLuint& gPosition;
GLuint& gMetallicRoughness;
GLuint& shadowGbuffer;
GLuint& irradianceMap;
GLuint& prefilterMap;
GLuint& brdfLUTTexture;
constexpr static GLuint gNormalBinding = 1,
gPositionBinding = 2,
gMetallicRoughnessBinding = 3,
gShadowMapBinding = 4,
irradianceMapBinding = 5,
prefilterMapBinding = 6,
brdfLUTBinding = 7;
};
class FinalPass : public RenderPass
{
public:
FinalPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, GLuint& gBaseColor, float& exposure);
void dispatch();
private:
Shader finalShader;
unsigned int& frameWidth;
unsigned int& frameHeight;
GLuint& gBaseColor;
float& exposure;
QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO;
constexpr static GLint gBaseColorBinding = 0;
};
class SkyboxPass : public RenderPass
{
public:
SkyboxPass(GladGLContext* gl, QMatrix4x4& projection, QMatrix4x4& view, float& exposure, GLuint& skyCubemap);
void dispatch();
private:
Shader skyBoxShader;
QMatrix4x4& projection;
QMatrix4x4& view;
float& exposure;
GLuint& skyCubemap;
constexpr static GLint environmentMapBinding = 0;
};
}

View File

@ -14,7 +14,6 @@
using namespace Renderer; using namespace Renderer;
QVector3D mainLightRadiance = 10 * 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;
@ -24,7 +23,6 @@ RendererGLWidget::RendererGLWidget(QWidget* parent)
, light(&camera) , light(&camera)
{ {
//startTimer(); //startTimer();
lastFrame = std::clock();
setFocusPolicy(Qt::StrongFocus); setFocusPolicy(Qt::StrongFocus);
//QSurfaceFormat format; //QSurfaceFormat format;
//format.setProfile(QSurfaceFormat::CoreProfile); //format.setProfile(QSurfaceFormat::CoreProfile);
@ -34,27 +32,6 @@ RendererGLWidget::RendererGLWidget(QWidget* parent)
RendererGLWidget::~RendererGLWidget() RendererGLWidget::~RendererGLWidget()
{ {
if (modelProgramPtr != nullptr)
{
makeCurrent();
delete modelProgramPtr;
modelProgramPtr = nullptr;
doneCurrent();
}
if (paintingProgramPtr != nullptr)
{
makeCurrent();
delete paintingProgramPtr;
paintingProgramPtr = nullptr;
doneCurrent();
}
if (finalProgramPtr != nullptr)
{
makeCurrent();
delete finalProgramPtr;
finalProgramPtr = nullptr;
doneCurrent();
}
} }
void RendererGLWidget::startTimer() void RendererGLWidget::startTimer()
@ -95,7 +72,7 @@ void RendererGLWidget::setModel(QString path)
void Renderer::RendererGLWidget::setMainLightRadiance(QVector3D radiance) void Renderer::RendererGLWidget::setMainLightRadiance(QVector3D radiance)
{ {
mainLightRadiance = radiance; light.radiance = radiance;
} }
void RendererGLWidget::setMainLightPitch(float pitch) void RendererGLWidget::setMainLightPitch(float pitch)
@ -151,45 +128,16 @@ void RendererGLWidget::initializeGL()
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
gl->ClearColor(0, 0, 0, 1); gl->ClearColor(0, 0, 0, 1);
shadowProgramPtr = new QOpenGLShaderProgram; vtManager = std::make_unique<VirtualTextureManager>(gl.get());
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert")) model = new Model(context(), vtManager.get());
qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Geometry, ":/Shaders/model_shadow.geom"))
qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag"))
qCritical() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->link())
qCritical() << "ERROR:" << shadowProgramPtr->log();
plainProgramPtr = new QOpenGLShaderProgram; shadowMapPass = std::make_unique<ShadowMapPass>(gl.get(), shadowFboHandle, shadowMapResolution, light, model);
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/shader.vert")) geometryPass = std::make_unique<GeometryPass>(gl.get(), frameWidth, frameHeight, fboPtr, model, projection, view);
qCritical() << "ERROR:" << plainProgramPtr->log(); pageIDCallbackPass = std::make_unique<PageIDCallbackPass>(gl.get(), frameWidth, frameHeight, fboPtr, gbuffers, gPageID, *vtManager);
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/shader.frag")) lightingPass = std::make_unique<LightingPass>(gl.get(), frameWidth, frameHeight, view, camera, light,
qCritical() << "ERROR:" << plainProgramPtr->log(); gBaseColor, gNormal, gPosition, gMetallicRoughness, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
if (!plainProgramPtr->link()) finalPass = std::make_unique<FinalPass>(gl.get(), frameWidth, frameHeight, gBaseColor, exposure);
qCritical() << "ERROR:" << plainProgramPtr->log(); skyboxPass = std::make_unique<SkyboxPass>(gl.get(), projection, view, exposure, skyCubemap);
modelProgramPtr = new QOpenGLShaderProgram;
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert"))
qCritical() << "ERROR:" << modelProgramPtr->log();
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model.frag"))
qCritical() << "ERROR:" << modelProgramPtr->log();
if (!modelProgramPtr->link())
qCritical() << "ERROR:" << modelProgramPtr->log();
paintingProgramPtr = new QOpenGLShaderProgram;
if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/painting.vert"))
qCritical() << "ERROR:" << paintingProgramPtr->log();
if (!paintingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/painting.frag"))
qCritical() << "ERROR:" << paintingProgramPtr->log();
if (!paintingProgramPtr->link())
qCritical() << "ERROR:" << paintingProgramPtr->log();
pageIdDownsampleProgramPtr = new QOpenGLShaderProgram;
if (!pageIdDownsampleProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/pageId_downsample.comp"))
qCritical() << "ERROR:" << pageIdDownsampleProgramPtr->log();
if (!pageIdDownsampleProgramPtr->link())
qCritical() << "ERROR:" << pageIdDownsampleProgramPtr->log();
depthInitProgramPtr = new QOpenGLShaderProgram; depthInitProgramPtr = new QOpenGLShaderProgram;
if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp")) if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp"))
@ -203,58 +151,16 @@ void RendererGLWidget::initializeGL()
if (!depthMipmapProgramPtr->link()) if (!depthMipmapProgramPtr->link())
qCritical() << "ERROR:" << depthMipmapProgramPtr->log(); qCritical() << "ERROR:" << depthMipmapProgramPtr->log();
shadowMappingProgramPtr = new QOpenGLShaderProgram;
if (!shadowMappingProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/shadow_mapping.comp"))
qCritical() << "ERROR:" << shadowMappingProgramPtr->log();
if (!shadowMappingProgramPtr->link())
qCritical() << "ERROR:" << shadowMappingProgramPtr->log();
ssgiProgramPtr = new QOpenGLShaderProgram; ssgiProgramPtr = new QOpenGLShaderProgram;
if (!ssgiProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/ssgi.comp")) if (!ssgiProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/ssgi.comp"))
qCritical() << "ERROR:" << ssgiProgramPtr->log(); qCritical() << "ERROR:" << ssgiProgramPtr->log();
if (!ssgiProgramPtr->link()) if (!ssgiProgramPtr->link())
qCritical() << "ERROR:" << ssgiProgramPtr->log(); qCritical() << "ERROR:" << ssgiProgramPtr->log();
finalProgramPtr = new QOpenGLShaderProgram;
if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/final.vert"))
qCritical() << "ERROR:" << finalProgramPtr->log();
if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/final.frag"))
qCritical() << "ERROR:" << finalProgramPtr->log();
if (!finalProgramPtr->link())
qCritical() << "ERROR:" << finalProgramPtr->log();
skyBoxProgramPtr = new QOpenGLShaderProgram;
if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/skybox.vert"))
qCritical() << "ERROR:" << skyBoxProgramPtr->log();
if (!skyBoxProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/skybox.frag"))
qCritical() << "ERROR:" << skyBoxProgramPtr->log();
if (!skyBoxProgramPtr->link())
qCritical() << "ERROR:" << skyBoxProgramPtr->log();
shadowProgramPtr->bind();
gl->GenBuffers(1, &lightSpaceMatricesUBO);
gl->BindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO);
gl->BufferData(GL_UNIFORM_BUFFER, sizeof(QMatrix4x4) * 16, nullptr, GL_STATIC_DRAW);
gl->BindBufferBase(GL_UNIFORM_BUFFER, 0, lightSpaceMatricesUBO);
gl->BindBuffer(GL_UNIFORM_BUFFER, 0);
shadowProgramPtr->release();
depthInitProgramPtr->bind(); depthInitProgramPtr->bind();
depthInitProgramPtr->setUniformValue("depthBuffer", 0); depthInitProgramPtr->setUniformValue("depthBuffer", 0);
depthInitProgramPtr->release(); depthInitProgramPtr->release();
shadowMappingProgramPtr->bind();
//shadowMappingProgramPtr->setUniformValue("gBaseColor", 0);
shadowMappingProgramPtr->setUniformValue("gNormal", 1);
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(); ssgiProgramPtr->bind();
ssgiProgramPtr->setUniformValue("gBaseColor", 0); ssgiProgramPtr->setUniformValue("gBaseColor", 0);
ssgiProgramPtr->setUniformValue("gNormal", 1); ssgiProgramPtr->setUniformValue("gNormal", 1);
@ -263,44 +169,21 @@ void RendererGLWidget::initializeGL()
ssgiProgramPtr->setUniformValue("gDepth", 4); ssgiProgramPtr->setUniformValue("gDepth", 4);
ssgiProgramPtr->setUniformValue("gDirectLight", 5); ssgiProgramPtr->setUniformValue("gDirectLight", 5);
finalProgramPtr->bind(); std::tie(skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture) = IblUtils::precomputeCubemaps(gl.get());
finalProgramPtr->setUniformValue("gBaseColor", 0);
finalProgramPtr->release();
vtManager = std::make_unique<VirtualTextureManager>(gl.get());
model = new Model(context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, vtManager.get());
skyBoxProgramPtr->bind();
skyBoxProgramPtr->setUniformValue("environmentMap", 0);
skyBoxProgramPtr->release();
std::tie(skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture) = IblUtils::precomputeCubemaps(glFunc);
quadVAO.create();
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
quadVBO.create();
quadVBO.bind();
GLfloat vertex[] = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
quadVBO.allocate(vertex, sizeof(vertex));
quadVBO.bind();
gl->EnableVertexAttribArray(0);
gl->VertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
nullptr);
gl->EnableVertexAttribArray(1);
gl->VertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
reinterpret_cast<void*>(3 * sizeof(GLfloat)));
quadVBO.release();
gl->GenQueries(1, &timeQuery); gl->GenQueries(1, &timeQuery);
} }
float calculateDeltaTime()
{
using namespace std::chrono;
static steady_clock::time_point last = steady_clock::now();
steady_clock::time_point current = steady_clock::now();
auto d = duration_cast<duration<float>>(current - last);
last = current;
return d.count();
}
void RendererGLWidget::paintGL() void RendererGLWidget::paintGL()
{ {
QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>(); QOpenGLFunctions_4_5_Core* glFunc = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Core>();
@ -314,184 +197,24 @@ void RendererGLWidget::paintGL()
light.lightDirection.setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw))); light.lightDirection.setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw)));
light.lightDirection.normalize(); light.lightDirection.normalize();
const std::vector<QMatrix4x4> lightMatrices = light.getLightSpaceMatrices(); projection = camera.GetProjectionMatrix();
gl->BindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO); view = camera.GetViewMatrix();
for (size_t i = 0; i < lightMatrices.size(); i++)
{
gl->BufferSubData(GL_UNIFORM_BUFFER, i * 16 * sizeof(GLfloat), 16 * sizeof(GLfloat), lightMatrices[i].data());
}
gl->BindBuffer(GL_UNIFORM_BUFFER, 0);
vtManager->commitMutex.lock(); vtManager->commitMutex.lock();
{ shadowMapPass->dispatch();
gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle); geometryPass->dispatch();
gl->Viewport(0, 0, shadowMapResolution, shadowMapResolution); pageIDCallbackPass->dispatch();
gl->Clear(GL_DEPTH_BUFFER_BIT);
//gl->CullFace(GL_FRONT);
if (model != nullptr)
model->drawShadow();
//gl->CullFace(GL_BACK);
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
}
QMatrix4x4 projection;
projection.perspective(camera.Zoom, camera.Ratio, camera.NearPlane, camera.FarPlane);
QMatrix4x4 view = camera.GetViewMatrix();
if (fboPtr->bind())
{
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl->Viewport(0, 0, frameWidth, frameHeight);
modelProgramPtr->bind();
modelProgramPtr->setUniformValue("projection", projection);
modelProgramPtr->setUniformValue("view", view);
modelProgramPtr->release();
paintingProgramPtr->bind();
paintingProgramPtr->setUniformValue("projection", projection);
paintingProgramPtr->setUniformValue("view", view);
paintingProgramPtr->release();
if (model != nullptr)
model->draw();
/// Debug Lighting
if (false)
{
plainProgramPtr->bind();
plainProgramPtr->setUniformValue("projection", projection);
plainProgramPtr->setUniformValue("view", view);
plainProgramPtr->setUniformValue("albedo", 0.5f, 0.5f, 0.5f);
QMatrix4x4 model;
int nrRows = 7, nrColumns = 7;
float spacing = 2.5;
for (int row = 0; row < nrRows; ++row)
{
plainProgramPtr->setUniformValue("metallic", (float)row / (float)nrRows);
for (int col = 0; col < nrColumns; ++col)
{
plainProgramPtr->setUniformValue("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f));
model.setToIdentity();
model.scale(10);
model.translate(QVector3D((float)(col - (nrColumns / 2)) * spacing,
(float)(row - (nrRows / 2)) * spacing + 20,
-2.0f));
plainProgramPtr->setUniformValue("model", model);
IblUtils::renderSphere(glFunc);
}
}
plainProgramPtr->release();
}
pageIdDownsampleProgramPtr->bind();
gl->BindImageTexture(3, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16UI);
gl->Uniform2ui(0, rand() % 8, rand() % 8);
gl->DispatchCompute(ceil(frameWidth / 8. / 8.), ceil(frameWidth / 8. / 8.), 1);
pageIdDownsampleProgramPtr->release();
std::vector<glm::u16vec2> pixels;
pixels.resize(ceil(frameWidth / 8.) * ceil(frameHeight / 8.));
//fboPtr->bind();
gl->ReadBuffer(GL_COLOR_ATTACHMENT4);
gl->ReadnPixels(0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
//gl->GetTextureSubImage(gbuffers[4], 0, 0, 0, 0, ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1, GL_RG_INTEGER, GL_UNSIGNED_SHORT, pixels.size() * sizeof(glm::u16vec2), pixels.data());
//fboPtr->release();
vtManager->tryUpdatePages(pixels);
fboPtr->release();
}
gl->Finish(); gl->Finish();
vtManager->commitMutex.unlock(); vtManager->commitMutex.unlock();
lightingPass->dispatch();
//depthInitProgramPtr->bind(); finalPass->dispatch();
//gl->ActiveTexture(GL_TEXTURE0); skyboxPass->dispatch();
//gl->BindTexture(GL_TEXTURE_2D, gbuffers[6]);
//gl->BindImageTexture(0, gbuffers[7], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
//gl->DispatchCompute(ceil(depthWidth / 8.), ceil(depthHeight / 8.), 1);
//depthInitProgramPtr->release();
//depthMipmapProgramPtr->bind();
//for (int i = 0; i <= 3; i++)
// gl->BindImageTexture(i, gbuffers[7], i, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
//gl->DispatchCompute(ceil(depthWidth / 2. / 8.), ceil(depthHeight / 2. / 8.), 1);
//for (int i = 0; i <= 3; i++)
// gl->BindImageTexture(i, gbuffers[7], i + 3, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
//gl->DispatchCompute(ceil(depthWidth / 2. / 8. / 8.), ceil(depthHeight / 2. / 8. / 8.), 1);
//depthMipmapProgramPtr->release();
shadowMappingProgramPtr->bind();
shadowMappingProgramPtr->setUniformValue("view", view);
shadowMappingProgramPtr->setUniformValue("farPlane", camera.FarPlane);
shadowMappingProgramPtr->setUniformValueArray("shadowCascadePlaneDistances", light.shadowCascadeLevels.data(), light.shadowCascadeLevels.size(), 1);
shadowMappingProgramPtr->setUniformValueArray("shadowBiases", light.frustumSizes.data(), light.frustumSizes.size(), 1);
//qDebug() << light.frustumSizes;
shadowMappingProgramPtr->setUniformValue("shadowCascadeCount", (GLint)light.shadowCascadeLevels.size());
shadowMappingProgramPtr->setUniformValue("shadowBlendRatio", light.blendRatio);
shadowMappingProgramPtr->setUniformValue("camPos", camera.Position);
shadowMappingProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
shadowMappingProgramPtr->setUniformValue("mainLightRadiance", mainLightRadiance);
gl->BindTextureUnit(1, gbuffers[1]);
gl->BindTextureUnit(2, gbuffers[2]);
gl->BindTextureUnit(3, gbuffers[3]);
gl->BindTextureUnit(4, shadowGbuffer);
gl->BindTextureUnit(5, irradianceMap);
gl->BindTextureUnit(6, prefilterMap);
gl->BindTextureUnit(7, brdfLUTTexture);
gl->BindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
gl->BindImageTexture(1, gbuffers[8], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F);
gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
shadowMappingProgramPtr->release();
/*ssgiProgramPtr->bind();
ssgiProgramPtr->setUniformValue("camPos", camera.Position);
ssgiProgramPtr->setUniformValue("cameraMatrix", projection * view);
ssgiProgramPtr->setUniformValue("projectionMatrix", projection);
ssgiProgramPtr->setUniformValue("viewMatrix", view);
ssgiProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
ssgiProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);
ssgiProgramPtr->setUniformValue("rdSeed", QVector4D(rand(), rand(), rand(), rand()));
gl->ActiveTexture(GL_TEXTURE0);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);
gl->ActiveTexture(GL_TEXTURE1);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[1]);
gl->ActiveTexture(GL_TEXTURE2);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[2]);
gl->ActiveTexture(GL_TEXTURE3);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[3]);
gl->ActiveTexture(GL_TEXTURE4);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[7]);
gl->ActiveTexture(GL_TEXTURE5);
gl->BindTexture(GL_TEXTURE_2D, gbuffers[8]);
gl->BindImageTexture(1, gbuffers[9], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA16F);
gl->DispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
ssgiProgramPtr->release();*/
gl->Viewport(0, 0, frameWidth, frameHeight);
gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
finalProgramPtr->bind();
finalProgramPtr->setUniformValue("exposure", exposure);
gl->BindTextureUnit(0, gbuffers[0]);
quadVAO.bind();
gl->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
quadVAO.release();
finalProgramPtr->release();
skyBoxProgramPtr->bind();
gl->Disable(GL_CULL_FACE);
skyBoxProgramPtr->setUniformValue("view", view);
skyBoxProgramPtr->setUniformValue("projection", projection);
skyBoxProgramPtr->setUniformValue("exposure", exposure);
gl->BindTextureUnit(0, skyCubemap);
IblUtils::renderCube(glFunc);
skyBoxProgramPtr->release();
gl->EndQuery(GL_TIME_ELAPSED); gl->EndQuery(GL_TIME_ELAPSED);
GLuint frameDuration; GLuint frameDuration;
gl->GetQueryObjectuiv(timeQuery, GL_QUERY_RESULT, &frameDuration); gl->GetQueryObjectuiv(timeQuery, GL_QUERY_RESULT, &frameDuration);
clock_t currentFrame = std::clock(); float deltaTime = calculateDeltaTime();
deltaTime = (float)(currentFrame - lastFrame) / CLOCKS_PER_SEC;
lastFrame = currentFrame;
static float accTime = 0, frameCnt = 0, averageDuration = 0; static float accTime = 0, frameCnt = 0, averageDuration = 0;
accTime += deltaTime; accTime += deltaTime;
@ -567,19 +290,19 @@ void RendererGLWidget::resizeGL(int width, int height)
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffers[3], 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffers[3], 0);
//gPaintingIndex //gPageID
gl->BindTexture(GL_TEXTURE_2D, gbuffers[4]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[4]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG16UI, frameWidth, frameHeight, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG16UI, frameWidth, frameHeight, 0, GL_RG_INTEGER, GL_UNSIGNED_INT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, gbuffers[4], 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, gbuffers[4], 0);
//PaintingTexCoord //PaintingTexCoord, Deprecated
gl->BindTexture(GL_TEXTURE_2D, gbuffers[5]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[5]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, frameWidth, frameHeight, 0, GL_RG, GL_FLOAT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, frameWidth, frameHeight, 0, GL_RG, GL_FLOAT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, gbuffers[5], 0); gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, gbuffers[5], 0);
//Depth //Depth, Deprecated
gl->BindTexture(GL_TEXTURE_2D, gbuffers[6]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[6]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, frameWidth, frameHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, frameWidth, frameHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -596,7 +319,7 @@ void RendererGLWidget::resizeGL(int width, int height)
if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "Framebuffer not complete!"; qDebug() << "Framebuffer not complete!";
//HiZ, not bind to fbo //HiZ, not bind to fbo, Deprecated
depthWidth = ceil(frameWidth / 64.) * 64; depthWidth = ceil(frameWidth / 64.) * 64;
depthHeight = ceil(frameHeight / 64.) * 64; depthHeight = ceil(frameHeight / 64.) * 64;
qDebug() << depthWidth << depthHeight; qDebug() << depthWidth << depthHeight;
@ -610,12 +333,12 @@ void RendererGLWidget::resizeGL(int width, int height)
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
gl->TexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f })); gl->TexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
//DirectLight //DirectLight, Deprecated
gl->BindTexture(GL_TEXTURE_2D, gbuffers[8]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[8]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, frameWidth, frameHeight, 0, GL_RGBA, GL_FLOAT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, frameWidth, frameHeight, 0, GL_RGBA, GL_FLOAT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//InDirectLight //InDirectLight, Deprecated
gl->BindTexture(GL_TEXTURE_2D, gbuffers[9]); gl->BindTexture(GL_TEXTURE_2D, gbuffers[9]);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, frameWidth, frameHeight, 0, GL_RGBA, GL_FLOAT, NULL); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, frameWidth, frameHeight, 0, GL_RGBA, GL_FLOAT, NULL);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -624,9 +347,6 @@ void RendererGLWidget::resizeGL(int width, int height)
fboPtr->release(); fboPtr->release();
} }
if (shadowFboHandle != 0) if (shadowFboHandle != 0)
{ {
gl->DeleteTextures(1, &shadowGbuffer); gl->DeleteTextures(1, &shadowGbuffer);
@ -663,7 +383,6 @@ void RendererGLWidget::resizeGL(int width, int height)
gl->BindFramebuffer(GL_FRAMEBUFFER, 0); gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
} }
std::cout << "\033[?25l"; std::cout << "\033[?25l";
} }

View File

@ -9,79 +9,88 @@
#include "Camera.h" #include "Camera.h"
#include "Light.h" #include "Light.h"
#include "Model.h" #include "Model.h"
#include "RenderPass.h"
struct GladGLContext; struct GladGLContext;
namespace Renderer namespace Renderer
{ {
class VirtualTextureManager; class VirtualTextureManager;
class RendererGLWidget : public QOpenGLWidget class RendererGLWidget : public QOpenGLWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
RendererGLWidget(QWidget* parent = nullptr); RendererGLWidget(QWidget* parent = nullptr);
~RendererGLWidget(); ~RendererGLWidget();
void startTimer(); void startTimer();
void stopTimer(); void stopTimer();
const std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>>& getPaintingMap(); const std::unordered_map<std::string, std::tuple<std::string, glm::vec2, glm::vec2>>& getPaintingMap();
public slots: public slots:
void setModel(QString path); void setModel(QString path);
void setMainLightRadiance(QVector3D radiance); void setMainLightRadiance(QVector3D radiance);
void setMainLightPitch(float pitch); void setMainLightPitch(float pitch);
void setMainLightYaw(float yaw); void setMainLightYaw(float yaw);
void setExposure(float exposure); void setExposure(float exposure);
protected: protected:
void initializeGL() override; void initializeGL() override;
void paintGL() override; void paintGL() override;
void resizeGL(int width, int height) override; void resizeGL(int width, int height) override;
void timerEvent(QTimerEvent* event) override; void timerEvent(QTimerEvent* event) override;
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override;
void wheelEvent(QWheelEvent* event) override; void wheelEvent(QWheelEvent* event) override;
void focusInEvent(QFocusEvent* event) override; void focusInEvent(QFocusEvent* event) override;
void focusOutEvent(QFocusEvent* event) override; void focusOutEvent(QFocusEvent* event) override;
private: private:
int timerId = -1; int timerId = -1;
int frameWidth, frameHeight; unsigned int frameWidth, frameHeight;
int depthWidth, depthHeight; int depthWidth, depthHeight;
QSet<int> pressedKeys; QSet<int> pressedKeys;
Camera camera; Camera camera;
Light light; Light light;
clock_t lastFrame; int shadowMapResolution;
float deltaTime; float exposure = 0.8;
int shadowMapResolution;
float exposure = 0.8;
std::unique_ptr<GladGLContext> gl; QMatrix4x4 projection;
QOpenGLShaderProgram* shadowProgramPtr = nullptr; QMatrix4x4 view;
QOpenGLShaderProgram* plainProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr;
QOpenGLShaderProgram* paintingProgramPtr = nullptr;
QOpenGLShaderProgram* pageIdDownsampleProgramPtr = nullptr;
QOpenGLShaderProgram* depthInitProgramPtr = nullptr;
QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr;
QOpenGLShaderProgram* shadowMappingProgramPtr = nullptr;
QOpenGLShaderProgram* ssgiProgramPtr = nullptr;
QOpenGLShaderProgram* finalProgramPtr = nullptr;
QOpenGLShaderProgram* skyBoxProgramPtr = nullptr;
QOpenGLFramebufferObject* fboPtr = nullptr;
GLuint gbuffers[10];
GLuint shadowFboHandle = 0;
GLuint shadowGbuffer;
GLuint lightSpaceMatricesUBO;
GLuint skyCubemap;
GLuint irradianceMap;
GLuint prefilterMap;
GLuint brdfLUTTexture;
QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO;
Model* model = nullptr;
std::unique_ptr<VirtualTextureManager> vtManager;
GLuint timeQuery; std::unique_ptr<GladGLContext> gl;
};
std::unique_ptr<ShadowMapPass> shadowMapPass;
std::unique_ptr<GeometryPass> geometryPass;
std::unique_ptr<PageIDCallbackPass> pageIDCallbackPass;
std::unique_ptr<LightingPass> lightingPass;
std::unique_ptr<FinalPass> finalPass;
std::unique_ptr<SkyboxPass> skyboxPass;
QOpenGLShaderProgram* depthInitProgramPtr = nullptr;
QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr;
QOpenGLShaderProgram* ssgiProgramPtr = nullptr;
QOpenGLFramebufferObject* fboPtr = nullptr;
GLuint gbuffers[10];
GLuint& gBaseColor = gbuffers[0];
GLuint& gNormal = gbuffers[1];
GLuint& gPosition = gbuffers[2];
GLuint& gMetallicRoughness = gbuffers[3];
GLuint& gPageID = gbuffers[4];
GLuint& gDirectLight = gbuffers[8];
GLuint shadowFboHandle = 0;
GLuint shadowGbuffer;
GLuint skyCubemap;
GLuint irradianceMap;
GLuint prefilterMap;
GLuint brdfLUTTexture;
Model* model = nullptr;
std::unique_ptr<VirtualTextureManager> vtManager;
GLuint timeQuery;
};
} }

View File

@ -0,0 +1,22 @@
#include "Shader.h"
namespace Renderer
{
Shader::Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath)
{
if (!addShaderFromSourceFile(QOpenGLShader::Vertex, vertexPath))
qCritical() << "COMPILE ERROR:" << log();
if (!addShaderFromSourceFile(QOpenGLShader::Fragment, fragmentPath))
qCritical() << "COMPILE ERROR:" << log();
if (geometryPath && !addShaderFromSourceFile(QOpenGLShader::Geometry, geometryPath))
qCritical() << "COMPILE ERROR:" << log();
if (!link())
qCritical() << "LINK ERROR:" << log();
}
Shader::Shader(const char* computePath)
{
if (!addShaderFromSourceFile(QOpenGLShader::Compute, computePath))
qCritical() << "COMPILE ERROR:" << log();
if (!link())
qCritical() << "LINK ERROR:" << log();
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <QOpenGLShaderProgram>
namespace Renderer
{
class Shader : public QOpenGLShaderProgram
{
public:
Shader(const char* vertexPath, const char* fragmentPath, const char* geometryPath = nullptr);
Shader(const char* computePath);
};
}