diff --git a/ToyEngine/ClassDiagram.cd b/ToyEngine/ClassDiagram.cd new file mode 100644 index 0000000..e937fce --- /dev/null +++ b/ToyEngine/ClassDiagram.cd @@ -0,0 +1,158 @@ + + + + + + AAABAAGwAAAAAAAQgEAAAAQAAAAAAAQAAAAACAABMAE= + src\Animation.h + + + + + + AAAAAAAAAAIAAAAAEQAABAEAAgAAAACgIAQAIAQAAgA= + src\Animator.h + + + + + + AMxAgQgABAAACAAAAAKAAAAABAAQAQQhCAAAAAAAAAA= + src\Particle.h + + + + + + BAEAIIAAAAAIgAAEAAKAIIACAAAgAAAiQAAAAAAIAgA= + src\Actor.h + + + + + + AIAAkAAAAAAAhAAQAAAEACAAAAJAAAAIAAAQIAAAAgA= + src\MainWindow.h + + + + + + AAAAgAAAAhQIBAAAAYIAACAAAAIAAAAgQAAAIAAAAAA= + src\World.h + + + + + + EAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAgA= + src\RenderPass.h + + + + + + AAAAEAAAAAAAAAAAoABAAIAAAAQAAAAAAAAAAAAIAAA= + src\RenderPass.h + + + + + + ABAgEAAAAADAAAAAAAAAAAAAAAAAQAAgAQCAAAAIAAA= + src\RenderPass.h + + + + + + AAAAAAAAEwAAAEAAAACQAAAAAAIAQAAgAwAAAAAIAAA= + src\RenderPass.h + + + + + + ACAAAAAABEAAAAAAAAAgAAIQAAAAQAAgAAAAAAAIAgA= + src\RenderPass.h + + + + + + ABAAAAACAAAAAAAAAgAAAAAQAAAAQAAAAQAAAAAIAAA= + src\RenderPass.h + + + + + + EAQAAAgAAIAAAFAEEAAAIAAAAAgQAwAAAAikEIQACAA= + src\Bone.h + + + + + + ADBAFBBAQQRAAgBAggGQAIIQAABAQAAgAwABAABAAgI= + src\RenderingSystem.h + + + + + + AABAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAQAAAAAAA= + src\PhysicsManager.h + + + + + + AAAAgAAAAAAIAAAAEEgAACAAAAAAAAAgAAAAIAEIBCA= + src\DemoWorld.h + + + + + + AAAAAAAAAAAAAAQAAAAAAABAAAAEAAAAAAAABAAAAAA= + src\Animation.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAIAAA= + src\Particle.h + + + + + + AIAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAA= + src\Bone.h + + + + + + AIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + src\Bone.h + + + + + + AIAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAA= + src\Bone.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAEADAAAgAAAAgAAAAA= + src\PhysicsManager.h + + + + \ No newline at end of file diff --git a/ToyEngine/ToyEngine.vcxproj b/ToyEngine/ToyEngine.vcxproj index df6cbda..dced617 100644 --- a/ToyEngine/ToyEngine.vcxproj +++ b/ToyEngine/ToyEngine.vcxproj @@ -32,6 +32,7 @@ + @@ -53,11 +54,13 @@ + + diff --git a/ToyEngine/ToyEngine.vcxproj.filters b/ToyEngine/ToyEngine.vcxproj.filters index 467f3cd..161e55d 100644 --- a/ToyEngine/ToyEngine.vcxproj.filters +++ b/ToyEngine/ToyEngine.vcxproj.filters @@ -63,6 +63,15 @@ 头文件 + + 头文件 + + + 头文件 + + + 头文件 + @@ -113,6 +122,15 @@ 源文件 + + 源文件 + + + 源文件 + + + 源文件 + @@ -166,5 +184,12 @@ Shaders + + + Shaders + + + Shaders + \ No newline at end of file diff --git a/ToyEngine/src/DemoWorld.cpp b/ToyEngine/src/DemoWorld.cpp index 0c8ae72..c469d66 100644 --- a/ToyEngine/src/DemoWorld.cpp +++ b/ToyEngine/src/DemoWorld.cpp @@ -1,14 +1,14 @@ #include "DemoWorld.h" #include "Particle.h" +#include "RenderingSystem.h" DemoWorld::DemoWorld() { + light.lightDirection = glm::normalize(glm::vec3((cos(lightPitch) * cos(lightYaw)), (sin(lightPitch)), (cos(lightPitch) * sin(lightYaw)))); + light.radiance = 15.f * lightColor; + std::string modelFilePath; - //modelFilePath = "E:\\3D Objects\\plane\\obj\\plane.obj"; - //modelFilePath = "E:\\3D Objects\\plane\\plane.gltf"; modelFilePath = "Models/vampire/vampire.gltf"; - //modelFilePath = "E:\\3D Objects\\cup\\cup.gltf"; - //modelFilePath = "E:\\3D Objects\\Sponza\\Sponza.gltf"; auto actor = std::make_shared(modelFilePath); actor->setRotaion(glm::angleAxis(glm::radians(-90.f), glm::vec3(1, 0, 0))); @@ -99,9 +99,9 @@ void DemoWorld::logicalTick(float deltaTime) mk2->setEnableGravity(true); } - if (mk2->getPosition().y < 7.5f && mk2->getSpeed().y<0) + if (mk2->getPosition().y < 7.5f && mk2->getSpeed().y < 0) { - particles[3]->setSpeed(particles[3]->getSpeed() + mk2->getSpeed()/2.f); + particles[3]->setSpeed(particles[3]->getSpeed() + mk2->getSpeed() / 2.f); mk2->setEnableGravity(false); mk2->setSpeed(glm::vec3(0)); mk2->setPosition({ 0,-100,0 }); @@ -111,6 +111,58 @@ void DemoWorld::logicalTick(float deltaTime) void DemoWorld::rendererTick(float deltaTime) { - World::rendererTick(deltaTime); } + +void DemoWorld::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_RIGHT) == GLFW_PRESS) + camera.processMouseMovement(xoffset, yoffset); +} + +void DemoWorld::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) +{ + if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) + lightPitch = glm::mod(lightPitch + yoffset / 100., glm::pi()); + else if (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) + lightYaw = glm::mod(lightYaw + yoffset / 100., 2 * glm::pi()); + else if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) + light.radiance = glm::clamp((light.radiance / lightColor).x + (float)yoffset, 0.f, 100.f) * lightColor; + else if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) + RenderingSystem::instance().exposure = glm::clamp(RenderingSystem::instance().exposure + (float)yoffset*0.1f, 0.f, 2.f); + else camera.processMouseScroll(yoffset); + + light.lightDirection = glm::normalize(glm::vec3((cos(lightPitch) * cos(lightYaw)), (sin(lightPitch)), (cos(lightPitch) * sin(lightYaw)))); +} + +void DemoWorld::processInput(GLFWwindow* window, float deltaTime) +{ + 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); +} diff --git a/ToyEngine/src/DemoWorld.h b/ToyEngine/src/DemoWorld.h index 66fb3cc..a9d0128 100644 --- a/ToyEngine/src/DemoWorld.h +++ b/ToyEngine/src/DemoWorld.h @@ -5,11 +5,19 @@ class DemoWorld : public World { public: DemoWorld(); - virtual void logicalTick(float deltaTime) override; - virtual void rendererTick(float deltaTime) override; + void logicalTick(float deltaTime) override; + void rendererTick(float deltaTime) override; + virtual void mouseCallback(GLFWwindow* window, double xpos, double ypos) override; + virtual void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) override; + virtual void processInput(GLFWwindow* window, float deltaTime) override; + private: std::vector> particles; std::shared_ptr throwPerson; std::shared_ptr mk2; + + glm::vec3 lightColor = glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784)); + float lightYaw = glm::radians(80.f); + float lightPitch = glm::radians(105.f); }; diff --git a/ToyEngine/src/IblUtils.cpp b/ToyEngine/src/IblUtils.cpp index 09ba63d..5d5695c 100644 --- a/ToyEngine/src/IblUtils.cpp +++ b/ToyEngine/src/IblUtils.cpp @@ -1,3 +1,4 @@ +#include #include "IblUtils.h" #include #include diff --git a/ToyEngine/src/IblUtils.h b/ToyEngine/src/IblUtils.h index 106371c..c91a6ad 100644 --- a/ToyEngine/src/IblUtils.h +++ b/ToyEngine/src/IblUtils.h @@ -1,8 +1,8 @@ #pragma once -#include #include #include +struct GladGLContext; class IblUtils { diff --git a/ToyEngine/src/Light.h b/ToyEngine/src/Light.h index 2abf503..1d458a1 100644 --- a/ToyEngine/src/Light.h +++ b/ToyEngine/src/Light.h @@ -4,14 +4,14 @@ #include #include #include -#include #include "Camera.h" -#include "Model.h" class Light { public: glm::vec3 lightDirection = glm::normalize(glm::vec3(0.2, 4, 0.4)); + glm::vec3 radiance = glm::vec3(0); + std::vector shadowCascadeLevels; float blendRatio = 0.3; std::vector frustumSizes; diff --git a/ToyEngine/src/MainWindow.cpp b/ToyEngine/src/MainWindow.cpp index 4f710f7..b3110d7 100644 --- a/ToyEngine/src/MainWindow.cpp +++ b/ToyEngine/src/MainWindow.cpp @@ -1,13 +1,10 @@ #include "MainWindow.h" -#include "IblUtils.h" -#include "RenderPass.h" -#include "World.h" #include "Particle.h" #include "DemoWorld.h" +#include "RenderingSystem.h" + MainWindow::MainWindow() - : camera(glm::vec3(0.0f, 0.0f, 3.0f)) - , light(&camera) { } @@ -21,9 +18,9 @@ int MainWindow::exec() GLFWmonitor* monitor = glfwGetPrimaryMonitor(); float xscale, yscale; glfwGetMonitorContentScale(monitor, &xscale, &yscale); - GLFWwindow* window = glfwCreateWindow(kWindowWidth * xscale, kWindowHeight * yscale, "ToyEngine", NULL, NULL); + window = glfwCreateWindow(kWindowWidth * xscale, kWindowHeight * yscale, "ToyEngine", NULL, NULL); glfwSetFramebufferSizeCallback(window, [](GLFWwindow* window, int width, int height) { - MainWindow::instance().framebufferSizeCallback(window, width, height); + RenderingSystem::instance().framebufferSizeCallback(window, width, height); }); glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) { MainWindow::instance().mouseCallback(window, xpos, ypos); @@ -44,38 +41,18 @@ int MainWindow::exec() 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, 0.0f); - gl->Enable(GL_DEPTH_TEST); - gl->DepthFunc(GL_LEQUAL); - gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); - gl->LineWidth(5 * xscale); + - std::unique_ptr world = std::make_unique(); + world = std::make_unique(); auto [minPos, maxPos] = world->getAABB(); std::cout << std::format("{},{},{} {},{},{}\n", minPos.x, minPos.y, minPos.z, maxPos.x, maxPos.y, maxPos.z); - light.sceneAABB = world->getAABB(); - - glm::mat4 projection, view; - auto [skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture] = IblUtils::precomputeCubemaps(gl.get()); - - ShadowMapPass shadowMapPass(gl.get(), shadowFboHandle, shadowMapResolution, *world, light); - GeometryPass geometryPass(gl.get(), frameWidth, frameHeight, fbo, *world, projection, view); - LightingPass lightingPass(gl.get(), frameWidth, frameHeight, view, camera, light, mainLightRadiance, - gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture); - FinalPass finalPass(gl.get(), frameWidth, frameHeight, gBaseColor, gDebug, exposure); - SkyboxPass skyboxPass(gl.get(), projection, view, exposure, skyCubemap); + RenderingSystem::instance().initialize(gl.get(), xscale, world.get()); int w, h; glfwGetFramebufferSize(window, &w, &h); - framebufferSizeCallback(window, w, h); + RenderingSystem::instance().framebufferSizeCallback(window, w, h); int logicalTickCount = 0; auto logicalThread = std::jthread([&](std::stop_token stop) { @@ -107,15 +84,7 @@ int MainWindow::exec() world->rendererTick(deltaTime); - projection = camera.getProjectionMatrix(); - view = camera.getViewMatrix(); - - shadowMapPass.dispatch(); - geometryPass.dispatch(); - lightingPass.dispatch(); - finalPass.setShowDebug(showDebug); - finalPass.dispatch(); - skyboxPass.dispatch(); + RenderingSystem::instance().tick(deltaTime); glfwSwapBuffers(window); glfwPollEvents(); @@ -126,7 +95,7 @@ int MainWindow::exec() if (accTime > 1.) { std::cout << std::format("{:20}\r", ""); - std::cout << std::format("FPS: {:.2f} TPS: {:.2f} {} {} {}\r", frameCnt / accTime, logicalTickCount / accTime, camera.Position.x, camera.Position.y, camera.Position.z); + std::cout << std::format("FPS: {:.2f} TPS: {:.2f}\r", frameCnt / accTime, logicalTickCount / accTime); accTime = 0; frameCnt = 0; logicalTickCount = 0; @@ -141,141 +110,24 @@ void MainWindow::processInput(GLFWwindow* window, float deltaTime) 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); - - static glm::mat4 transform(1); - float speed = 1; - if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) - transform = glm::translate(transform, glm::vec3(0, 0, speed)); - if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) - transform = glm::translate(transform, glm::vec3(0, 0, -speed)); - if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) - transform = glm::translate(transform, glm::vec3(-speed, 0, 0)); - if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) - transform = glm::translate(transform, glm::vec3(speed, 0, 0)); - //modelPtr->setTransform(transform); -} - -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->CreateTextures(GL_TEXTURE_2D, gbuffers.size(), gbuffers.data()); - gl->TextureStorage2D(gBaseColor, 1, GL_RGBA8, frameWidth, frameHeight); - gl->TextureStorage2D(gNormal, 1, GL_RGB16F, frameWidth, frameHeight); - gl->TextureStorage2D(gPosition, 1, GL_RGB32F, frameWidth, frameHeight); - gl->TextureStorage2D(gMetallicRoughness, 1, GL_RG8, frameWidth, frameHeight); - gl->TextureStorage2D(gDebug, 1, GL_RGBA8, frameWidth, frameHeight); - - std::vector attachments; - for (auto i = 0U; i < gbuffers.size(); i++) - { - gl->TextureParameteri(gbuffers[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl->TextureParameteri(gbuffers[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->NamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0 + i, gbuffers[i], 0); - attachments.push_back(GL_COLOR_ATTACHMENT0 + i); - } - gl->NamedFramebufferDrawBuffers(fbo, attachments.size(), attachments.data()); - gl->CreateRenderbuffers(1, &rboDepth); - gl->NamedRenderbufferStorage(rboDepth, GL_DEPTH_COMPONENT, frameWidth, frameHeight); - gl->NamedFramebufferRenderbuffer(fbo, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth); - - if (gl->CheckNamedFramebufferStatus(fbo, GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - std::cerr << "Framebuffer not complete!\n"; - } - - 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); - } - + world->processInput(window, deltaTime); } 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; - static 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); + world->mouseCallback(window, xpos, ypos); } void MainWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - camera.processMouseScroll(yoffset); + world->scrollCallback(window, xoffset, yoffset); } void MainWindow::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_TAB && action == GLFW_PRESS) - showDebug = !showDebug; + RenderingSystem::instance().setShowDebug(!RenderingSystem::instance().getShowDebug()); + world->keyCallback(window, key, scancode, action, mods); } MainWindow& MainWindow::instance() @@ -287,4 +139,9 @@ MainWindow& MainWindow::instance() GladGLContext* MainWindow::getGLContext() { return instance().gl.get(); -} \ No newline at end of file +} + +GLFWwindow* MainWindow::getWindow() +{ + return window; +} diff --git a/ToyEngine/src/MainWindow.h b/ToyEngine/src/MainWindow.h index 2b90c08..4bd891e 100644 --- a/ToyEngine/src/MainWindow.h +++ b/ToyEngine/src/MainWindow.h @@ -1,21 +1,20 @@ #pragma once -#include "Model.h" -#include "Camera.h" -#include "Light.h" -#include #include +#include #include +#include "World.h" + class MainWindow { public: static MainWindow& instance(); static GladGLContext* getGLContext(); + GLFWwindow* getWindow(); 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 keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); @@ -23,29 +22,9 @@ private: static constexpr int kWindowWidth = 1200; static constexpr int kWindowHeight = 675; - unsigned int frameWidth; - unsigned int frameHeight; - - Camera camera; - Light light; - glm::vec3 mainLightRadiance = 30.f * glm::normalize(glm::vec3(0.7529, 0.7450, 0.6784)); - float exposure = 0.6f; - + + GLFWwindow* window = nullptr; std::unique_ptr gl; - - GLuint fbo = 0; - std::array gbuffers; - GLuint& gBaseColor = gbuffers[0]; - GLuint& gNormal = gbuffers[1]; - GLuint& gPosition = gbuffers[2]; - GLuint& gMetallicRoughness = gbuffers[3]; - GLuint& gDebug = gbuffers[4]; - GLuint rboDepth = 0; - - GLuint shadowFboHandle = 0; - GLuint shadowGbuffer; - int shadowMapResolution; - - bool showDebug = false; + std::unique_ptr world; }; diff --git a/ToyEngine/src/Model.cpp b/ToyEngine/src/Model.cpp index 2e4b475..75d7642 100644 --- a/ToyEngine/src/Model.cpp +++ b/ToyEngine/src/Model.cpp @@ -1,3 +1,4 @@ +#include #include "Model.h" #include #include diff --git a/ToyEngine/src/Model.h b/ToyEngine/src/Model.h index 4f8c07f..65d99be 100644 --- a/ToyEngine/src/Model.h +++ b/ToyEngine/src/Model.h @@ -1,5 +1,4 @@ #pragma once -#include #include #include #include diff --git a/ToyEngine/src/Particle.cpp b/ToyEngine/src/Particle.cpp index a083b3a..695f5c6 100644 --- a/ToyEngine/src/Particle.cpp +++ b/ToyEngine/src/Particle.cpp @@ -20,7 +20,7 @@ Particle::Particle(float mass, const std::string& path) void Particle::logicalTick(float deltaTime) { resultantForce = glm::vec3(0); - for (auto& force : forces) + for (std::lock_guard lk(forcesMutex); auto & force : forces) resultantForce += force->value; if (fixed) @@ -32,13 +32,8 @@ void Particle::logicalTick(float deltaTime) //auto pos = getPosition() + speed * deltaTime + 0.5f * resultantForce / mass * deltaTime * deltaTime; speed += resultantForce / mass * deltaTime; auto pos = getPosition() + speed * deltaTime; - //if (speed.y < 0 && pos.y < 0.4) - //{ - // speed.y = -speed.y; - //} setPosition(pos); } - } void Particle::draw(const RenderPassContext& context, Shader& shader) @@ -71,7 +66,7 @@ void Particle::draw(const RenderPassContext& context, Shader& shader) debugShader.setUniformValue("view", *context.view); glm::mat4 modelMatrix = glm::translate(glm::mat4(1), getPosition());// *glm::scale(glm::mat4(1), glm::vec3(glm::abs(resultantForce / mass))); gl->BindVertexArray(vao); - for (auto& force : forces) + for (std::lock_guard lk(forcesMutex); auto & force : forces) { debugShader.setUniformValue("model", modelMatrix * glm::scale(glm::mat4(1), glm::vec3(1)) * glm::mat4_cast(glm::rotation(glm::vec3(1, 0, 0), glm::normalize(force->value)))); debugShader.setUniformValue("color", glm::vec3(0, 1, 0)); @@ -85,11 +80,13 @@ void Particle::draw(const RenderPassContext& context, Shader& shader) void Particle::addForce(std::shared_ptr force) { + std::lock_guard lk(forcesMutex); forces.insert(force); } void Particle::removeForce(std::shared_ptr force) { + std::lock_guard lk(forcesMutex); forces.erase(force); } diff --git a/ToyEngine/src/Particle.h b/ToyEngine/src/Particle.h index a0a2e73..0496b58 100644 --- a/ToyEngine/src/Particle.h +++ b/ToyEngine/src/Particle.h @@ -18,6 +18,7 @@ public: virtual void draw(const RenderPassContext& context, Shader& shader); void addForce(std::shared_ptr force); void removeForce(std::shared_ptr force); + std::mutex forcesMutex; float getMass(); glm::vec3 getSpeed(); void setSpeed(const glm::vec3& speed); diff --git a/ToyEngine/src/RenderPass.cpp b/ToyEngine/src/RenderPass.cpp index d168cd6..7964536 100644 --- a/ToyEngine/src/RenderPass.cpp +++ b/ToyEngine/src/RenderPass.cpp @@ -1,14 +1,14 @@ +#include #include "RenderPass.h" #include "IblUtils.h" #include "Mesh.h" -ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world, Light& light) +ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world) : RenderPass(gl, { typeid(ShadowMapPass) }) , modelShadowShader(gl, "Shaders/model_shadow.vert", "Shaders/model_shadow.frag", "Shaders/model_shadow.geom") , shadowFboHandle(shadowFboHandle) , shadowMapResolution(shadowMapResolution) , world(world) - , light(light) { gl->CreateBuffers(1, &lightSpaceMatricesUBO); gl->NamedBufferData(lightSpaceMatricesUBO, sizeof(glm::mat4) * 16, nullptr, GL_STATIC_DRAW); @@ -17,7 +17,7 @@ ShadowMapPass::ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& sh void ShadowMapPass::dispatch() { - const auto lightMatrices = light.getLightSpaceMatrices(); + const auto lightMatrices = world.light.getLightSpaceMatrices(); gl->NamedBufferSubData(lightSpaceMatricesUBO, 0, lightMatrices.size() * sizeof(lightMatrices[0]), lightMatrices.data()); gl->BindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle); @@ -89,7 +89,7 @@ void GeometryPass::dispatch() gl->BindFramebuffer(GL_FRAMEBUFFER, 0); } -LightingPass::LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, glm::mat4& view, Camera& camera, Light& light, glm::vec3& mainLightRadiance, std::array& gbuffers, GLuint& shadowGbuffer, GLuint& irradianceMap, GLuint& prefilterMap, GLuint& brdfLUTTexture) +LightingPass::LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, glm::mat4& view, Camera& camera, Light& light, std::array& gbuffers, GLuint& shadowGbuffer, GLuint& irradianceMap, GLuint& prefilterMap, GLuint& brdfLUTTexture) : RenderPass(gl, { typeid(LightingPass) }) , pbrShader(gl, "Shaders/pbr.comp") , frameWidth(frameWidth) @@ -97,7 +97,6 @@ LightingPass::LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned , view(view) , camera(camera) , light(light) - , mainLightRadiance(mainLightRadiance) , gbuffers(gbuffers) , shadowGbuffer(shadowGbuffer) , irradianceMap(irradianceMap) @@ -126,7 +125,7 @@ void LightingPass::dispatch() pbrShader.setUniformValue("shadowBlendRatio", light.blendRatio); pbrShader.setUniformValue("camPos", camera.Position); pbrShader.setUniformValue("mainLightDirection", light.lightDirection); - pbrShader.setUniformValue("mainLightRadiance", mainLightRadiance); + pbrShader.setUniformValue("mainLightRadiance", light.radiance); gl->BindTextureUnit(1, gbuffers[1]); gl->BindTextureUnit(2, gbuffers[2]); diff --git a/ToyEngine/src/RenderPass.h b/ToyEngine/src/RenderPass.h index 3f9b980..05e141e 100644 --- a/ToyEngine/src/RenderPass.h +++ b/ToyEngine/src/RenderPass.h @@ -1,5 +1,4 @@ #pragma once -#include #include "Shader.h" #include "World.h" #include "Light.h" @@ -20,14 +19,13 @@ protected: class ShadowMapPass : public RenderPass { public: - ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world, Light& light); + ShadowMapPass(GladGLContext* gl, GLuint& shadowFboHandle, int& shadowMapResolution, World& world); void dispatch(); private: Shader modelShadowShader; GLuint& shadowFboHandle; int& shadowMapResolution; World& world; - Light& light; GLuint lightSpaceMatricesUBO; }; @@ -52,7 +50,7 @@ class LightingPass : public RenderPass { public: LightingPass(GladGLContext* gl, unsigned int& frameWidth, unsigned int& frameHeight, - glm::mat4& view, Camera& camera, Light& light, glm::vec3& mainLightRadiance, + glm::mat4& view, Camera& camera, Light& light, std::array& gbuffers, GLuint& shadowGbuffer, GLuint& irradianceMap, GLuint& prefilterMap, GLuint& brdfLUTTexture); void dispatch(); @@ -63,7 +61,6 @@ private: glm::mat4& view; Camera& camera; Light& light; - glm::vec3& mainLightRadiance; std::array& gbuffers; GLuint& shadowGbuffer; GLuint& irradianceMap; diff --git a/ToyEngine/src/RenderingSystem.cpp b/ToyEngine/src/RenderingSystem.cpp new file mode 100644 index 0000000..55029b6 --- /dev/null +++ b/ToyEngine/src/RenderingSystem.cpp @@ -0,0 +1,136 @@ +#include +#include "RenderingSystem.h" +#include "IblUtils.h" + +RenderingSystem::RenderingSystem() +{ +} + +void RenderingSystem::initialize(GladGLContext* gl, float pixelRatio, World* world) +{ + world->light.sceneAABB = world->getAABB(); + + this->gl = gl; + this->world = world; + + 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, 0.0f); + gl->Enable(GL_DEPTH_TEST); + gl->DepthFunc(GL_LEQUAL); + gl->Enable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + gl->LineWidth(5 * pixelRatio); + + std::tie(skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture) = IblUtils::precomputeCubemaps(gl); + + shadowMapPass = std::make_unique(gl, shadowFboHandle, shadowMapResolution, *world); + geometryPass = std::make_unique(gl, frameWidth, frameHeight, fbo, *world, projection, view); + lightingPass = std::make_unique(gl, frameWidth, frameHeight, view, world->camera, world->light, + gbuffers, shadowGbuffer, irradianceMap, prefilterMap, brdfLUTTexture); + finalPass = std::make_unique(gl, frameWidth, frameHeight, gBaseColor, gDebug, exposure); + skyboxPass = std::make_unique(gl, projection, view, exposure, skyCubemap); +} + +void RenderingSystem::tick(float deltaTime) +{ + projection = world->camera.getProjectionMatrix(); + view = world->camera.getViewMatrix(); + + shadowMapPass->dispatch(); + geometryPass->dispatch(); + lightingPass->dispatch(); + + finalPass->dispatch(); + skyboxPass->dispatch(); +} + +RenderingSystem& RenderingSystem::instance() +{ + static RenderingSystem renderingSystem; + return renderingSystem; +} + +bool RenderingSystem::getShowDebug() +{ + return finalPass->getShowDebug(); +} + +void RenderingSystem::setShowDebug(bool showDebug) +{ + finalPass->setShowDebug(showDebug); +} + +void RenderingSystem::framebufferSizeCallback(GLFWwindow* window, int width, int height) +{ + frameWidth = width; + frameHeight = height; + world->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->CreateTextures(GL_TEXTURE_2D, gbuffers.size(), gbuffers.data()); + gl->TextureStorage2D(gBaseColor, 1, GL_RGBA8, frameWidth, frameHeight); + gl->TextureStorage2D(gNormal, 1, GL_RGB16F, frameWidth, frameHeight); + gl->TextureStorage2D(gPosition, 1, GL_RGB32F, frameWidth, frameHeight); + gl->TextureStorage2D(gMetallicRoughness, 1, GL_RG8, frameWidth, frameHeight); + gl->TextureStorage2D(gDebug, 1, GL_RGBA8, frameWidth, frameHeight); + + std::vector attachments; + for (auto i = 0U; i < gbuffers.size(); i++) + { + gl->TextureParameteri(gbuffers[i], GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TextureParameteri(gbuffers[i], GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->NamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0 + i, gbuffers[i], 0); + attachments.push_back(GL_COLOR_ATTACHMENT0 + i); + } + gl->NamedFramebufferDrawBuffers(fbo, attachments.size(), attachments.data()); + gl->CreateRenderbuffers(1, &rboDepth); + gl->NamedRenderbufferStorage(rboDepth, GL_DEPTH_COMPONENT, frameWidth, frameHeight); + gl->NamedFramebufferRenderbuffer(fbo, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepth); + + if (gl->CheckNamedFramebufferStatus(fbo, GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + std::cerr << "Framebuffer not complete!\n"; + } + + 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)world->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); + } + +} \ No newline at end of file diff --git a/ToyEngine/src/RenderingSystem.h b/ToyEngine/src/RenderingSystem.h new file mode 100644 index 0000000..e1651cd --- /dev/null +++ b/ToyEngine/src/RenderingSystem.h @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include "Model.h" +#include "Camera.h" +#include "Light.h" +#include "World.h" +#include "RenderPass.h" +#include "MainWindow.h" + +class RenderingSystem +{ +public: + static RenderingSystem& instance(); + void initialize(GladGLContext* gl, float pixelRatio, World* world); + void tick(float deltaTime); + void framebufferSizeCallback(GLFWwindow* window, int width, int height); + bool getShowDebug(); + void setShowDebug(bool showDebug); + + float exposure = 0.6f; + +private: + RenderingSystem(); + + unsigned int frameWidth; + unsigned int frameHeight; + + glm::mat4 projection, view; + World* world; + + GladGLContext* gl; + + GLuint skyCubemap, irradianceMap, prefilterMap, brdfLUTTexture; + + GLuint fbo = 0; + std::array gbuffers; + GLuint& gBaseColor = gbuffers[0]; + GLuint& gNormal = gbuffers[1]; + GLuint& gPosition = gbuffers[2]; + GLuint& gMetallicRoughness = gbuffers[3]; + GLuint& gDebug = gbuffers[4]; + GLuint rboDepth = 0; + + GLuint shadowFboHandle = 0; + GLuint shadowGbuffer; + int shadowMapResolution; + + std::unique_ptr shadowMapPass; + std::unique_ptr geometryPass; + std::unique_ptr lightingPass; + std::unique_ptr finalPass; + std::unique_ptr skyboxPass; +}; + diff --git a/ToyEngine/src/Shader.cpp b/ToyEngine/src/Shader.cpp index 4e18fe7..acecd6f 100644 --- a/ToyEngine/src/Shader.cpp +++ b/ToyEngine/src/Shader.cpp @@ -1,3 +1,4 @@ +#include #include "Shader.h" Shader::Shader(GladGLContext* gl, const char* vertexPath, const char* fragmentPath, const char* geometryPath) diff --git a/ToyEngine/src/Shader.h b/ToyEngine/src/Shader.h index 752e6cb..9a1db7d 100644 --- a/ToyEngine/src/Shader.h +++ b/ToyEngine/src/Shader.h @@ -1,7 +1,6 @@ #ifndef SHADER_H #define SHADER_H -#include #include #include diff --git a/ToyEngine/src/World.cpp b/ToyEngine/src/World.cpp index 7d73ed7..87b5959 100644 --- a/ToyEngine/src/World.cpp +++ b/ToyEngine/src/World.cpp @@ -1,5 +1,11 @@ #include "World.h" +World::World() + : camera(glm::vec3(0.0f, 0.0f, 3.0f)) + , light(&camera) +{ +} + void World::logicalTick(float deltaTime) { physicsManager.tick(deltaTime); diff --git a/ToyEngine/src/World.h b/ToyEngine/src/World.h index 03bbc92..f2bec0c 100644 --- a/ToyEngine/src/World.h +++ b/ToyEngine/src/World.h @@ -2,17 +2,29 @@ #include "Actor.h" #include "RenderPassContext.h" #include "PhysicsManager.h" +#include "Camera.h" +#include "Light.h" +#include class World { public: + Camera camera; + Light light; std::vector> actors; + + World(); virtual void logicalTick(float deltaTime); virtual void rendererTick(float deltaTime); void draw(const RenderPassContext& context, Shader& shader); void addActor(std::shared_ptr actor); std::pair getAABB(); + virtual void mouseCallback(GLFWwindow* window, double xpos, double ypos) {}; + virtual void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) {}; + virtual void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {}; + virtual void processInput(GLFWwindow* window, float deltaTime) {}; protected: PhysicsManager physicsManager; + };