添加MainWIndow类
parent
b06f08cd84
commit
6234a31673
|
@ -26,6 +26,7 @@
|
||||||
<ClInclude Include="src\Camera.h" />
|
<ClInclude Include="src\Camera.h" />
|
||||||
<ClInclude Include="src\IblUtils.h" />
|
<ClInclude Include="src\IblUtils.h" />
|
||||||
<ClInclude Include="src\Light.h" />
|
<ClInclude Include="src\Light.h" />
|
||||||
|
<ClInclude Include="src\MainWindow.h" />
|
||||||
<ClInclude Include="src\Mesh.h" />
|
<ClInclude Include="src\Mesh.h" />
|
||||||
<ClInclude Include="src\Model.h" />
|
<ClInclude Include="src\Model.h" />
|
||||||
<ClInclude Include="src\RenderPass.h" />
|
<ClInclude Include="src\RenderPass.h" />
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
<ClCompile Include="src\IblUtils.cpp" />
|
<ClCompile Include="src\IblUtils.cpp" />
|
||||||
<ClCompile Include="src\Light.cpp" />
|
<ClCompile Include="src\Light.cpp" />
|
||||||
<ClCompile Include="src\main.cpp" />
|
<ClCompile Include="src\main.cpp" />
|
||||||
|
<ClCompile Include="src\MainWindow.cpp" />
|
||||||
<ClCompile Include="src\Mesh.cpp" />
|
<ClCompile Include="src\Mesh.cpp" />
|
||||||
<ClCompile Include="src\Model.cpp" />
|
<ClCompile Include="src\Model.cpp" />
|
||||||
<ClCompile Include="src\RenderPass.cpp" />
|
<ClCompile Include="src\RenderPass.cpp" />
|
||||||
|
|
|
@ -51,6 +51,9 @@
|
||||||
<ClInclude Include="src\Actor.h">
|
<ClInclude Include="src\Actor.h">
|
||||||
<Filter>头文件</Filter>
|
<Filter>头文件</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\MainWindow.h">
|
||||||
|
<Filter>头文件</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\gl.c">
|
<ClCompile Include="src\gl.c">
|
||||||
|
@ -89,6 +92,9 @@
|
||||||
<ClCompile Include="src\Actor.cpp">
|
<ClCompile Include="src\Actor.cpp">
|
||||||
<Filter>源文件</Filter>
|
<Filter>源文件</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\MainWindow.cpp">
|
||||||
|
<Filter>源文件</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Shaders\brdf_lut.comp">
|
<None Include="Shaders\brdf_lut.comp">
|
||||||
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
#include "MainWindow.h"
|
||||||
|
#include "IblUtils.h"
|
||||||
|
#include "RenderPass.h"
|
||||||
|
|
||||||
|
MainWindow::MainWindow()
|
||||||
|
: camera(glm::vec3(0.0f, 0.0f, 3.0f))
|
||||||
|
, light(&camera)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::processInput(GLFWwindow* window)
|
||||||
|
{
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
|
||||||
|
glfwSetWindowShouldClose(window, true);
|
||||||
|
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(FORWARD, deltaTime);
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(BACKWARD, deltaTime);
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(LEFT, deltaTime);
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(RIGHT, deltaTime);
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(UP, deltaTime);
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
||||||
|
camera.processKeyboard(DOWN, deltaTime);
|
||||||
|
|
||||||
|
glm::mat4 transform(1);
|
||||||
|
float speed = 1;
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
|
||||||
|
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, speed)));
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
|
||||||
|
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, -speed)));
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
|
||||||
|
modelPtr->setTransform(glm::translate(transform, glm::vec3(-speed, 0, 0)));
|
||||||
|
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
|
||||||
|
modelPtr->setTransform(glm::translate(transform, glm::vec3(speed, 0, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::framebufferSizeCallback(GLFWwindow* window, int width, int height)
|
||||||
|
{
|
||||||
|
frameWidth = width;
|
||||||
|
frameHeight = height;
|
||||||
|
camera.Ratio = (float)frameWidth / (float)frameHeight;
|
||||||
|
if (fbo)
|
||||||
|
{
|
||||||
|
gl->DeleteRenderbuffers(1, &rboDepth);
|
||||||
|
gl->DeleteTextures(gbuffers.size(), gbuffers.data());
|
||||||
|
gl->DeleteFramebuffers(1, &fbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
gl->CreateFramebuffers(1, &fbo);
|
||||||
|
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
{
|
||||||
|
gl->GenTextures(gbuffers.size(), gbuffers.data());
|
||||||
|
//BaseColor
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);
|
||||||
|
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameWidth, frameHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gbuffers[0], 0);
|
||||||
|
//Normal
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, gbuffers[1]);
|
||||||
|
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gbuffers[1], 0);
|
||||||
|
//Position
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, gbuffers[2]);
|
||||||
|
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gbuffers[2], 0);
|
||||||
|
//MetallicRoughness
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D, gbuffers[3]);
|
||||||
|
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG8, frameWidth, frameHeight, 0, GL_RG, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
|
||||||
|
|
||||||
|
std::array<GLenum, 4> attachments = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
|
||||||
|
gl->DrawBuffers(attachments.size(), attachments.data());
|
||||||
|
gl->GenRenderbuffers(1, &rboDepth);
|
||||||
|
gl->BindRenderbuffer(GL_RENDERBUFFER, rboDepth);
|
||||||
|
gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, frameWidth, frameHeight);
|
||||||
|
gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
|
||||||
|
if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
std::cerr << "Framebuffer not complete!\n";
|
||||||
|
|
||||||
|
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowFboHandle != 0)
|
||||||
|
{
|
||||||
|
gl->DeleteTextures(1, &shadowGbuffer);
|
||||||
|
gl->DeleteFramebuffers(1, &shadowFboHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowMapResolution = 2048;
|
||||||
|
gl->GenFramebuffers(1, &shadowFboHandle);
|
||||||
|
{
|
||||||
|
gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
|
||||||
|
gl->GenTextures(1, &shadowGbuffer);
|
||||||
|
//Depth
|
||||||
|
gl->BindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
|
||||||
|
gl->TexImage3D(
|
||||||
|
GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, shadowMapResolution, shadowMapResolution, (int)light.shadowCascadeLevels.size(),
|
||||||
|
0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
|
||||||
|
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
gl->TexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
|
||||||
|
gl->FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowGbuffer, 0);
|
||||||
|
gl->DrawBuffer(GL_NONE);
|
||||||
|
gl->ReadBuffer(GL_NONE);
|
||||||
|
|
||||||
|
if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
std::cerr << "ShadowFramebuffer not complete!\n";
|
||||||
|
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::mouseCallback(GLFWwindow* window, double xpos, double ypos)
|
||||||
|
{
|
||||||
|
static bool firstMouse = true;
|
||||||
|
static float lastX;
|
||||||
|
static float lastY;
|
||||||
|
|
||||||
|
float xoffset = xpos - lastX;
|
||||||
|
float yoffset = lastY - ypos;
|
||||||
|
|
||||||
|
lastX = xpos;
|
||||||
|
lastY = ypos;
|
||||||
|
|
||||||
|
if (firstMouse)
|
||||||
|
{
|
||||||
|
firstMouse = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
|
||||||
|
{
|
||||||
|
float speed = 0.2f;
|
||||||
|
glm::mat4 rotate(1);
|
||||||
|
rotate = glm::rotate(rotate, glm::radians(glm::length(glm::vec2(xoffset, yoffset)) * speed), glm::vec3(glm::vec2(-yoffset, xoffset), 0.0));
|
||||||
|
modelPtr->setTransform(rotate);
|
||||||
|
}
|
||||||
|
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
|
||||||
|
camera.processMouseMovement(xoffset, yoffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
||||||
|
{
|
||||||
|
camera.processMouseScroll(yoffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow& MainWindow::instance()
|
||||||
|
{
|
||||||
|
static MainWindow window;
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MainWindow::exec()
|
||||||
|
{
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
|
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||||
|
float xscale, yscale;
|
||||||
|
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
|
||||||
|
GLFWwindow* window = glfwCreateWindow(kWindowWidth * xscale, kWindowHeight * yscale, "RenderModel", NULL, NULL);
|
||||||
|
MainWindow& m = *this;
|
||||||
|
glfwSetFramebufferSizeCallback(window, [](GLFWwindow* window, int width, int height) {
|
||||||
|
MainWindow::instance().framebufferSizeCallback(window, width, height);
|
||||||
|
});
|
||||||
|
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) {
|
||||||
|
MainWindow::instance().mouseCallback(window, xpos, ypos);
|
||||||
|
});
|
||||||
|
glfwSetScrollCallback(window, [](GLFWwindow* window, double xoffset, double yoffset) {
|
||||||
|
MainWindow::instance().scrollCallback(window, xoffset, yoffset);
|
||||||
|
});
|
||||||
|
int xpos, ypos, width, height;
|
||||||
|
glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height);
|
||||||
|
glfwSetWindowPos(window, xpos + (width - (kWindowWidth * xscale)) / 2, ypos + (height - kWindowHeight * yscale) / 2);
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
gl = std::make_unique<GladGLContext>();
|
||||||
|
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)glfwGetProcAddress(name); }))
|
||||||
|
{
|
||||||
|
std::cout << "Failed to initialize GLAD" << std::endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gl->Enable(GL_DEBUG_OUTPUT);
|
||||||
|
//gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
|
gl->DebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) {
|
||||||
|
if (type == GL_DEBUG_TYPE_ERROR)
|
||||||
|
std::cerr << std::format("GL_ERROR: type = {:#x}, severity = {:#x}, message = {}", type, severity, message);
|
||||||
|
}, 0);
|
||||||
|
gl->ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
gl->Enable(GL_DEPTH_TEST);
|
||||||
|
gl->DepthFunc(GL_LEQUAL);
|
||||||
|
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||||
|
|
||||||
|
std::string modelFilePath;
|
||||||
|
//modelFilePath = "E:\\3D Objects\\plane\\obj\\plane.obj";
|
||||||
|
//modelFilePath = "E:\\3D Objects\\plane\\plane.gltf";
|
||||||
|
modelFilePath = "E:\\3D Objects\\vampire/gltf/vampire.gltf";
|
||||||
|
//modelFilePath = "E:\\3D Objects\\cup\\cup.gltf";
|
||||||
|
//modelFilePath = "E:\\3D Objects\\Sponza\\Sponza.gltf";
|
||||||
|
|
||||||
|
Model model(gl.get(), modelFilePath);
|
||||||
|
modelPtr = &model;
|
||||||
|
light.model = &model;
|
||||||
|
|
||||||
|
Animation danceAnimation(modelFilePath, &model);
|
||||||
|
Animator animator(&danceAnimation);
|
||||||
|
|
||||||
|
glm::mat4 projection, view;
|
||||||
|
auto [skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture] = IblUtils::precomputeCubemaps(gl.get());
|
||||||
|
|
||||||
|
ShadowMapPass shadowMapPass(gl.get(), shadowFboHandle, shadowMapResolution, model, light);
|
||||||
|
GeometryPass geometryPass(gl.get(), frameWidth, frameHeight, fbo, model, projection, view, animator);
|
||||||
|
LightingPass lightingPass(gl.get(), frameWidth, frameHeight, view, camera, light, mainLightRadiance,
|
||||||
|
gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
|
||||||
|
FinalPass finalPass(gl.get(), frameWidth, frameHeight, gbuffers, exposure);
|
||||||
|
SkyboxPass skyboxPass(gl.get(), projection, view, exposure, skyCubemap);
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
glfwGetFramebufferSize(window, &w, &h);
|
||||||
|
framebufferSizeCallback(window, w, h);
|
||||||
|
|
||||||
|
while (!glfwWindowShouldClose(window))
|
||||||
|
{
|
||||||
|
float currentFrame = glfwGetTime();
|
||||||
|
deltaTime = currentFrame - lastFrame;
|
||||||
|
lastFrame = currentFrame;
|
||||||
|
processInput(window);
|
||||||
|
|
||||||
|
animator.UpdateAnimation(deltaTime);
|
||||||
|
|
||||||
|
projection = camera.getProjectionMatrix();
|
||||||
|
view = camera.getViewMatrix();
|
||||||
|
|
||||||
|
shadowMapPass.dispatch();
|
||||||
|
geometryPass.dispatch();
|
||||||
|
lightingPass.dispatch();
|
||||||
|
finalPass.dispatch();
|
||||||
|
skyboxPass.dispatch();
|
||||||
|
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Model.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
#include "Light.h"
|
||||||
|
#include <array>
|
||||||
|
#include <glad/gl.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
class MainWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static MainWindow& instance();
|
||||||
|
int exec();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MainWindow();
|
||||||
|
void framebufferSizeCallback(GLFWwindow* window, int width, int height);
|
||||||
|
void mouseCallback(GLFWwindow* window, double xpos, double ypos);
|
||||||
|
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||||
|
void processInput(GLFWwindow* window);
|
||||||
|
|
||||||
|
static constexpr int kWindowWidth = 1200;
|
||||||
|
static constexpr int kWindowHeight = 675;
|
||||||
|
unsigned int frameWidth;
|
||||||
|
unsigned int frameHeight;
|
||||||
|
|
||||||
|
Model* modelPtr = nullptr;
|
||||||
|
Camera camera;
|
||||||
|
Light light;
|
||||||
|
glm::vec3 mainLightRadiance = 40.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784));
|
||||||
|
float exposure = 1;
|
||||||
|
|
||||||
|
float deltaTime = 0.0f;
|
||||||
|
float lastFrame = 0.0f;
|
||||||
|
|
||||||
|
std::unique_ptr<GladGLContext> gl;
|
||||||
|
|
||||||
|
GLuint fbo = 0;
|
||||||
|
std::array<GLuint, 4> gbuffers;
|
||||||
|
GLuint rboDepth = 0;
|
||||||
|
GLuint shadowFboHandle = 0;
|
||||||
|
GLuint shadowGbuffer;
|
||||||
|
int shadowMapResolution;
|
||||||
|
};
|
||||||
|
|
|
@ -1,299 +1,12 @@
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include <stb_image.h>
|
#include <stb_image.h>
|
||||||
#include <glad/gl.h>
|
#include "MainWindow.h"
|
||||||
#include <GLFW/glfw3.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
|
||||||
#include "Shader.h"
|
|
||||||
#include "camera.h"
|
|
||||||
#include "Model.h"
|
|
||||||
#include "IblUtils.h"
|
|
||||||
#include "Light.h"
|
|
||||||
#include "RenderPass.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <array>
|
|
||||||
#include <format>
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "Animator.h"
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
_declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
_declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
void framebufferSizeCallback(GLFWwindow* window, int width, int height);
|
|
||||||
void mouseCallback(GLFWwindow* window, double xpos, double ypos);
|
|
||||||
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
|
||||||
void processInput(GLFWwindow* window);
|
|
||||||
|
|
||||||
constexpr int windowWidth = 1200;
|
|
||||||
constexpr int windowHeight = 675;
|
|
||||||
unsigned int frameWidth;
|
|
||||||
unsigned int frameHeight;
|
|
||||||
|
|
||||||
Model* modelPtr = nullptr;
|
|
||||||
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
|
|
||||||
Light light(&camera);
|
|
||||||
glm::vec3 mainLightRadiance = 40.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784));
|
|
||||||
float exposure = 1;
|
|
||||||
|
|
||||||
float deltaTime = 0.0f;
|
|
||||||
float lastFrame = 0.0f;
|
|
||||||
|
|
||||||
std::unique_ptr<GladGLContext> gl;
|
|
||||||
|
|
||||||
GLuint fbo = 0;
|
|
||||||
std::array<GLuint, 4> gbuffers;
|
|
||||||
GLuint rboDepth = 0;
|
|
||||||
GLuint shadowFboHandle = 0;
|
|
||||||
GLuint shadowGbuffer;
|
|
||||||
int shadowMapResolution;
|
|
||||||
|
|
||||||
void GLAPIENTRY messageCallback(GLenum source,
|
|
||||||
GLenum type,
|
|
||||||
GLuint id,
|
|
||||||
GLenum severity,
|
|
||||||
GLsizei length,
|
|
||||||
const GLchar* message,
|
|
||||||
const void* userParam)
|
|
||||||
{
|
|
||||||
if (type == GL_DEBUG_TYPE_ERROR)
|
|
||||||
std::cerr << std::format("GL_ERROR: type = {:#x}, severity = {:#x}, message = {}",
|
|
||||||
type, severity, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
glfwInit();
|
return MainWindow::instance().exec();
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
||||||
|
|
||||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
|
||||||
float xscale, yscale;
|
|
||||||
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
|
|
||||||
GLFWwindow* window = glfwCreateWindow(windowWidth * xscale, windowHeight * yscale, "RenderModel", NULL, NULL);
|
|
||||||
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
|
|
||||||
glfwSetCursorPosCallback(window, mouseCallback);
|
|
||||||
glfwSetScrollCallback(window, scrollCallback);
|
|
||||||
int xpos, ypos, width, height;
|
|
||||||
glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &width, &height);
|
|
||||||
glfwSetWindowPos(window, xpos + (width - (windowWidth * xscale)) / 2, ypos + (height - windowHeight * yscale) / 2);
|
|
||||||
glfwMakeContextCurrent(window);
|
|
||||||
gl = std::make_unique<GladGLContext>();
|
|
||||||
if (!gladLoadGLContext(gl.get(), [](const char* name) { return (GLADapiproc)glfwGetProcAddress(name); }))
|
|
||||||
{
|
|
||||||
std::cout << "Failed to initialize GLAD" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
gl->Enable(GL_DEBUG_OUTPUT);
|
|
||||||
//gl->Enable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
||||||
gl->DebugMessageCallback(messageCallback, 0);
|
|
||||||
gl->ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
gl->Enable(GL_DEPTH_TEST);
|
|
||||||
gl->DepthFunc(GL_LEQUAL);
|
|
||||||
gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
|
||||||
|
|
||||||
std::string modelFilePath;
|
|
||||||
//modelFilePath = "E:\\3D Objects\\plane\\obj\\plane.obj";
|
|
||||||
//modelFilePath = "E:\\3D Objects\\plane\\plane.gltf";
|
|
||||||
modelFilePath = "E:\\3D Objects\\vampire/gltf/vampire.gltf";
|
|
||||||
//modelFilePath = "E:\\3D Objects\\cup\\cup.gltf";
|
|
||||||
//modelFilePath = "E:\\3D Objects\\Sponza\\Sponza.gltf";
|
|
||||||
|
|
||||||
Model model(gl.get(), modelFilePath);
|
|
||||||
modelPtr = &model;
|
|
||||||
light.model = &model;
|
|
||||||
|
|
||||||
Animation danceAnimation(modelFilePath, &model);
|
|
||||||
Animator animator(&danceAnimation);
|
|
||||||
|
|
||||||
glm::mat4 projection, view;
|
|
||||||
auto [skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture] = IblUtils::precomputeCubemaps(gl.get());
|
|
||||||
|
|
||||||
ShadowMapPass shadowMapPass(gl.get(), shadowFboHandle, shadowMapResolution, model, light);
|
|
||||||
GeometryPass geometryPass(gl.get(), frameWidth, frameHeight, fbo, model, projection, view, animator);
|
|
||||||
LightingPass lightingPass(gl.get(), frameWidth, frameHeight, view, camera, light, mainLightRadiance,
|
|
||||||
gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture);
|
|
||||||
FinalPass finalPass(gl.get(), frameWidth, frameHeight, gbuffers, exposure);
|
|
||||||
SkyboxPass skyboxPass(gl.get(), projection, view, exposure, skyCubemap);
|
|
||||||
|
|
||||||
int w, h;
|
|
||||||
glfwGetFramebufferSize(window, &w, &h);
|
|
||||||
framebufferSizeCallback(window, w, h);
|
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window))
|
|
||||||
{
|
|
||||||
float currentFrame = glfwGetTime();
|
|
||||||
deltaTime = currentFrame - lastFrame;
|
|
||||||
lastFrame = currentFrame;
|
|
||||||
processInput(window);
|
|
||||||
|
|
||||||
animator.UpdateAnimation(deltaTime);
|
|
||||||
|
|
||||||
projection = camera.getProjectionMatrix();
|
|
||||||
view = camera.getViewMatrix();
|
|
||||||
|
|
||||||
shadowMapPass.dispatch();
|
|
||||||
geometryPass.dispatch();
|
|
||||||
lightingPass.dispatch();
|
|
||||||
finalPass.dispatch();
|
|
||||||
skyboxPass.dispatch();
|
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
|
||||||
glfwPollEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwTerminate();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void processInput(GLFWwindow* window)
|
|
||||||
{
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
|
|
||||||
glfwSetWindowShouldClose(window, true);
|
|
||||||
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(FORWARD, deltaTime);
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(BACKWARD, deltaTime);
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(LEFT, deltaTime);
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(RIGHT, deltaTime);
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(UP, deltaTime);
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
|
||||||
camera.processKeyboard(DOWN, deltaTime);
|
|
||||||
|
|
||||||
glm::mat4 transform(1);
|
|
||||||
float speed = 1;
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS)
|
|
||||||
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, speed)));
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS)
|
|
||||||
modelPtr->setTransform(glm::translate(transform, glm::vec3(0, 0, -speed)));
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS)
|
|
||||||
modelPtr->setTransform(glm::translate(transform, glm::vec3(-speed, 0, 0)));
|
|
||||||
if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS)
|
|
||||||
modelPtr->setTransform(glm::translate(transform, glm::vec3(speed, 0, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void framebufferSizeCallback(GLFWwindow* window, int width, int height)
|
|
||||||
{
|
|
||||||
frameWidth = width;
|
|
||||||
frameHeight = height;
|
|
||||||
camera.Ratio = (float)frameWidth / (float)frameHeight;
|
|
||||||
if (fbo)
|
|
||||||
{
|
|
||||||
gl->DeleteRenderbuffers(1, &rboDepth);
|
|
||||||
gl->DeleteTextures(gbuffers.size(), gbuffers.data());
|
|
||||||
gl->DeleteFramebuffers(1, &fbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
gl->CreateFramebuffers(1, &fbo);
|
|
||||||
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
||||||
{
|
|
||||||
gl->GenTextures(gbuffers.size(), gbuffers.data());
|
|
||||||
//BaseColor
|
|
||||||
gl->BindTexture(GL_TEXTURE_2D, gbuffers[0]);
|
|
||||||
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frameWidth, frameHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gbuffers[0], 0);
|
|
||||||
//Normal
|
|
||||||
gl->BindTexture(GL_TEXTURE_2D, gbuffers[1]);
|
|
||||||
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gbuffers[1], 0);
|
|
||||||
//Position
|
|
||||||
gl->BindTexture(GL_TEXTURE_2D, gbuffers[2]);
|
|
||||||
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gbuffers[2], 0);
|
|
||||||
//MetallicRoughness
|
|
||||||
gl->BindTexture(GL_TEXTURE_2D, gbuffers[3]);
|
|
||||||
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG8, frameWidth, frameHeight, 0, GL_RG, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
|
|
||||||
|
|
||||||
std::array<GLenum, 4> attachments = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
|
|
||||||
gl->DrawBuffers(attachments.size(), attachments.data());
|
|
||||||
gl->GenRenderbuffers(1, &rboDepth);
|
|
||||||
gl->BindRenderbuffer(GL_RENDERBUFFER, rboDepth);
|
|
||||||
gl->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, frameWidth, frameHeight);
|
|
||||||
gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth);
|
|
||||||
if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
||||||
std::cerr << "Framebuffer not complete!\n";
|
|
||||||
|
|
||||||
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shadowFboHandle != 0)
|
|
||||||
{
|
|
||||||
gl->DeleteTextures(1, &shadowGbuffer);
|
|
||||||
gl->DeleteFramebuffers(1, &shadowFboHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
shadowMapResolution = 2048;
|
|
||||||
gl->GenFramebuffers(1, &shadowFboHandle);
|
|
||||||
{
|
|
||||||
gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
|
|
||||||
gl->GenTextures(1, &shadowGbuffer);
|
|
||||||
//Depth
|
|
||||||
gl->BindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
|
|
||||||
gl->TexImage3D(
|
|
||||||
GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, shadowMapResolution, shadowMapResolution, (int)light.shadowCascadeLevels.size(),
|
|
||||||
0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
|
|
||||||
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
|
||||||
gl->TexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
|
||||||
gl->TexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
|
|
||||||
gl->FramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowGbuffer, 0);
|
|
||||||
gl->DrawBuffer(GL_NONE);
|
|
||||||
gl->ReadBuffer(GL_NONE);
|
|
||||||
|
|
||||||
if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
||||||
std::cerr << "ShadowFramebuffer not complete!\n";
|
|
||||||
gl->BindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void mouseCallback(GLFWwindow* window, double xpos, double ypos)
|
|
||||||
{
|
|
||||||
static bool firstMouse = true;
|
|
||||||
static float lastX;
|
|
||||||
static float lastY;
|
|
||||||
|
|
||||||
float xoffset = xpos - lastX;
|
|
||||||
float yoffset = lastY - ypos;
|
|
||||||
|
|
||||||
lastX = xpos;
|
|
||||||
lastY = ypos;
|
|
||||||
|
|
||||||
if (firstMouse)
|
|
||||||
{
|
|
||||||
firstMouse = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
|
|
||||||
{
|
|
||||||
float speed = 0.2f;
|
|
||||||
glm::mat4 rotate(1);
|
|
||||||
rotate = glm::rotate(rotate, glm::radians(glm::length(glm::vec2(xoffset, yoffset)) * speed), glm::vec3(glm::vec2(-yoffset, xoffset), 0.0));
|
|
||||||
modelPtr->setTransform(rotate);
|
|
||||||
}
|
|
||||||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
|
|
||||||
camera.processMouseMovement(xoffset, yoffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset)
|
|
||||||
{
|
|
||||||
camera.processMouseScroll(yoffset);
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue