From 3bbb233716143ea31b7f1390d4b17751aa8d4997 Mon Sep 17 00:00:00 2001 From: Hurlu Date: Mon, 17 Jun 2019 22:32:53 +0900 Subject: [PATCH] Proof that deferred shading is way better at handling a lot of lights --- BaseGLProject/ModelView.h | 1 - BaseGLProject/Multipass.cpp | 27 +++----- BaseGLProject/Multipass.h | 6 +- BaseGLProject/MyGLWindow.cpp | 128 +++++++++++++++++++++-------------- BaseGLProject/MyGLWindow.h | 14 +++- BaseGLProject/SceneContext.h | 12 ---- BaseGLProject/Source.cpp | 51 ++++++++++++-- BaseGLProject/imgui.ini | 6 +- 8 files changed, 149 insertions(+), 96 deletions(-) diff --git a/BaseGLProject/ModelView.h b/BaseGLProject/ModelView.h index 62c7bef..1de57dc 100644 --- a/BaseGLProject/ModelView.h +++ b/BaseGLProject/ModelView.h @@ -20,7 +20,6 @@ public: void glTranslate(float x, float y, float z) { - glm::mat4 Trans = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z)); modelstack.top() = modelstack.top() * Trans; } diff --git a/BaseGLProject/Multipass.cpp b/BaseGLProject/Multipass.cpp index 53605b8..9d68d6c 100644 --- a/BaseGLProject/Multipass.cpp +++ b/BaseGLProject/Multipass.cpp @@ -66,14 +66,14 @@ void Multipass::enableFrameBufferTexture(const std::string tex_name) glBindFramebuffer(GL_FRAMEBUFFER, _fboId); } -void Multipass::gBufferSetup(SceneContext &scnctx, std::map &meshes) +void Multipass::gBufferSetup(SceneContext &scnctx, std::vector>& meshes) { if (shader != nullptr) delete(shader); shader = new Shader("textureViewer.vert", "textureViewer.frag"); shader->addUniform("tex", 0); for (auto mesh : meshes) - mesh.second->shader = std::make_shared("DSGeometryPass.vert", "DSGeometryPass.frag"); + mesh->shader = std::make_shared("DSGeometryPass.vert", "DSGeometryPass.frag"); scnctx.firstRedraw = false; } @@ -93,7 +93,7 @@ void Multipass::recomputeDeferredLights(SceneContext &scnctx) shader->addUniform("NLights", (int)scnctx.lights.size()); } -void Multipass::deferredLightSetup(SceneContext &scnctx, std::map &meshes) +void Multipass::deferredLightSetup(SceneContext &scnctx, std::vector>& meshes) { if (shader != nullptr) delete(shader); @@ -104,7 +104,7 @@ void Multipass::deferredLightSetup(SceneContext &scnctx, std::mapaddUniform("color_tex", 2); for (auto mesh : meshes) - mesh.second->shader = std::make_shared("DSGeometryPass.vert", "DSGeometryPass.frag"); + mesh->shader = std::make_shared("DSGeometryPass.vert", "DSGeometryPass.frag"); recomputeDeferredLights(scnctx); @@ -114,7 +114,8 @@ void Multipass::deferredLightSetup(SceneContext &scnctx, std::mapdisable(); } -void Multipass::forwardLightSetup(SceneContext &scnctx, std::map &meshes) +void Multipass::forwardLightSetup(SceneContext &scnctx, std::vector>& meshes) { if (shader != nullptr) delete(shader); shader = nullptr; for (auto mesh : meshes) { - mesh.second->shader = std::make_shared("tex_base_light.vert", "tex_base_light.frag"); - mesh.second->shader->addUniform("tex", 0); + mesh->shader = std::make_shared("tex_base_light.vert", "tex_base_light.frag"); + mesh->shader->addUniform("tex", 0); } scnctx.firstRedraw = false; @@ -181,11 +177,6 @@ void Multipass::drawGBufferToScreen(SceneContext & scnctx) glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - static GLuint clearColor[4] = { 0, 0, 0, 0 }; - glClearTexImage(_pass_textures["position_buffer"], 0, GL_BGRA, GL_UNSIGNED_BYTE, &clearColor); - glClearTexImage(_pass_textures["normal_buffer"], 0, GL_BGRA, GL_UNSIGNED_BYTE, &clearColor); - glClearTexImage(_pass_textures["color_buffer"], 0, GL_BGRA, GL_UNSIGNED_BYTE, &clearColor); - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/BaseGLProject/Multipass.h b/BaseGLProject/Multipass.h index c9721e3..8137e36 100644 --- a/BaseGLProject/Multipass.h +++ b/BaseGLProject/Multipass.h @@ -22,13 +22,13 @@ public: void enableFrameBufferTexture(const std::string tex_name); - void gBufferSetup(SceneContext &scnctx, std::map &meshes); + void gBufferSetup(SceneContext &scnctx, std::vector>& meshes); void recomputeDeferredLights(SceneContext &scnctx); void drawGBufferToScreen(SceneContext &scnctx); - void deferredLightSetup(SceneContext &scnctx, std::map &meshes); + void deferredLightSetup(SceneContext &scnctx, std::vector>& meshes); void drawDeferredLightToScreen(SceneContext &scnctx); - void forwardLightSetup(SceneContext &scnctx, std::map &meshes); + void forwardLightSetup(SceneContext &scnctx, std::vector>& meshes); diff --git a/BaseGLProject/MyGLWindow.cpp b/BaseGLProject/MyGLWindow.cpp index df28c04..042016c 100644 --- a/BaseGLProject/MyGLWindow.cpp +++ b/BaseGLProject/MyGLWindow.cpp @@ -48,8 +48,7 @@ MyGlWindow::MyGlWindow(int w, int h) : } MyGlWindow::~MyGlWindow() -{ - shaders.clear(); +{ } void MyGlWindow::draw() @@ -67,6 +66,74 @@ void MyGlWindow::setBgColor(float bgColor[3]) scnctx.bg = glm::vec4(bgColor[0], bgColor[1], bgColor[2], 1); } +void MyGlWindow::orbitLights(float timePassed, float speed) +{ + float angle = timePassed * speed; + + for (auto &&light : scnctx.lights) + { + glm::mat4 rotate = glm::rotate(glm::mat4(1.0f), + glm::radians(angle), glm::vec3(0, 1, 0)); + light.location = rotate * light.location; + } + + if (scnctx.renderMode == DEFERRED_LIGHT) + multipassManager.recomputeDeferredLights(scnctx); +} + +void MyGlWindow::loadScene(SceneChoice scene) +{ + meshes.clear(); + scnctx.lights.clear(); + + float pos_x = -20; + float pos_z = -20; + Dataset moddata; + switch (scene) + { + case MOUNTAIN: + meshes.emplace_back(std::make_shared("mountain/mount.blend1.obj", "DSGeometryPass.vert", "DSGeometryPass.frag")); + scnctx.lights.emplace_back(glm::vec3(1, 1, 1), glm::vec4(0, 2, 2, 1)); + break; + case CUBES: + moddata.simpleCube(); + std::srand(18); + + for (int i = 1; i < 401; i++) + { + meshes.emplace_back(std::make_shared(moddata, "DSGeometryPass.vert", "DSGeometryPass.frag")); + meshes[meshes.size() - 1]->textures["0"] = scnctx.textures["BrickTex"]; + + meshes[meshes.size() - 1]->addStartRotation(glm::vec4(1, -1, 1, 90)); + meshes[meshes.size() - 1]->addStartTranslation(glm::vec4(0, 1, 0, 0)); + meshes[meshes.size() - 1]->addStartTranslation(glm::vec4(pos_x, 0, 0, 0)); + meshes[meshes.size() - 1]->addStartTranslation(glm::vec4(0, 0, pos_z, 0)); + pos_x += 2; + + if (i % 20 == 0) + { + pos_x = -20; + pos_z += 2; + } + + } + for (int i = 0; i < 64; i++) + { + float light_r = (std::rand() % 10) / 100.f; + float light_g = (std::rand() % 10) / 100.f; + float light_b = (std::rand() % 10) / 100.f; + scnctx.lights.emplace_back(glm::vec3(light_r, light_g, light_b), + glm::vec4(std::rand() % 40 - 20, std::rand() % 3 + 3, std::rand() % 40 - 20, 1)); + } + + break; + default: + break; + } + this->scene = scene; + scnctx.firstRedraw = true; +} + void MyGlWindow::textureSetup() { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -120,47 +187,7 @@ void MyGlWindow::setup() textureSetup(); multipassSetup(); - Dataset moddata; - - - //Scene for GBuffer Testing - Mesh *mountain = new Mesh("mountain/mount.blend1.obj", "DSGeometryPass.vert", "DSGeometryPass.frag"); - - meshes.emplace("mountain", mountain); - - scnctx.lights.emplace_back(glm::vec3(1, 1, 1), glm::vec4(0, 2, 0, 1)); - - - //Scene for light testing - - //moddata.simpleCube(); - - //Hardcoded seed for easy scene replication - //std::srand(18); - - //int zob = std::rand(); - //for (int i = 0; i < 20; i++) - //{ - // //std::string cube_name = "Cube" + std::to_string(i); - // //meshes.emplace(cube_name, new Mesh(moddata, "DSGeometryPass.vert", "DSGeometryPass.frag")); - // //meshes[cube_name]->textures["0"] = _scnctx.textures["BrickTex"]; - // // - // float pos_x = std::rand() % 100 - 50; - // float pos_z = std::rand() % 100 - 50; - - // //meshes[cube_name]->addStartTranslation(glm::vec4(0, 1, 0, 0)); - // //meshes[cube_name]->addStartTranslation(glm::vec4(pos_x, 0, 0, 0)); - // //meshes[cube_name]->addStartTranslation(glm::vec4(0, 0, pos_z, 0)); - // //meshes[cube_name]->addStartRotation(glm::vec4(1, 0, 0, std::rand() % 360)); - // //meshes[cube_name]->addStartRotation(glm::vec4(0, 1, 0, std::rand() % 360)); - // //meshes[cube_name]->addStartRotation(glm::vec4(0, 0, 1, std::rand() % 360)); - // - // float light_r = (40 + std::rand() % 60) / 100.f; - // float light_g = (40 + std::rand() % 60) / 100.f; - // float light_b = (40 + std::rand() % 60) / 100.f; - // - // scnctx.lights.emplace_back(glm::vec3(light_r, light_g, light_b), glm::vec4(pos_x, 2, pos_z, 1)); - //} + loadScene(MOUNTAIN); } void MyGlWindow::drawDeferredLight() @@ -177,7 +204,6 @@ void MyGlWindow::drawDeferredLight() glm::mat4 view = lookAt(eye, look, up); //Calculate view matrix from parameters of m_viewer glm::mat4 projection = perspective(45.0f, (float)scnctx.width / (float)scnctx.height, 0.1f, 1000.0f); - scnctx.camPos = eye; scnctx.viewMatrix = view; scnctx.projectionMatrix = projection; @@ -189,7 +215,7 @@ void MyGlWindow::drawDeferredLight() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (auto it = meshes.begin(); it != meshes.end(); it++) - (*it).second->draw(scnctx); + (*it)->draw(scnctx); multipassManager.drawDeferredLightToScreen(scnctx); } @@ -219,7 +245,7 @@ void MyGlWindow::drawDebugGBuffer() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); for (auto it = meshes.begin(); it != meshes.end(); it++) - (*it).second->draw(scnctx); + (*it)->draw(scnctx); multipassManager.drawGBufferToScreen(scnctx); @@ -250,17 +276,17 @@ void MyGlWindow::drawForwardLight() for (auto it = meshes.begin(); it != meshes.end(); it++) { - (*it).second->shader->addUniform("view_pos", scnctx.camPos); + (*it)->shader->addUniform("view_pos", scnctx.camPos); int i = 0; for (auto light : scnctx.lights) { - (*it).second->shader->addUniform("lights[" + std::to_string(i) + "].Position", glm::vec3(light.location)); - (*it).second->shader->addUniform("lights[" + std::to_string(i) + "].Color", light.intensity); + (*it)->shader->addUniform("lights[" + std::to_string(i) + "].Position", glm::vec3(light.location)); + (*it)->shader->addUniform("lights[" + std::to_string(i) + "].Color", light.intensity); i++; } - (*it).second->shader->addUniform("NLights", (int)scnctx.lights.size()); - (*it).second->draw(scnctx); + (*it)->shader->addUniform("NLights", (int)scnctx.lights.size()); + (*it)->draw(scnctx); } } diff --git a/BaseGLProject/MyGLWindow.h b/BaseGLProject/MyGLWindow.h index 7a298c7..5e349c1 100644 --- a/BaseGLProject/MyGLWindow.h +++ b/BaseGLProject/MyGLWindow.h @@ -13,6 +13,12 @@ #include "imgui/stb_image.h" #include "Multipass.h" +enum SceneChoice +{ + MOUNTAIN, + CUBES +}; + struct vertexAttr { GLfloat posX, posY, posZ; GLfloat r, g, b; @@ -25,15 +31,17 @@ public: void draw(); void setBgColor(float bgColor[3]); - - std::map shaders; - std::map meshes; + void orbitLights(float timePassed, float speed); + void loadScene(SceneChoice scene); + + std::vector> meshes; void resize(int w, int h); Viewer viewer; SceneContext scnctx; Multipass multipassManager; + SceneChoice scene; private: int m_width; int m_height; diff --git a/BaseGLProject/SceneContext.h b/BaseGLProject/SceneContext.h index 17d2ec5..3ff1e81 100644 --- a/BaseGLProject/SceneContext.h +++ b/BaseGLProject/SceneContext.h @@ -39,16 +39,4 @@ struct SceneContext RenderMode renderMode; bool firstRedraw; - - void adjustSpots() - { - for (auto it : lights) - { - if (it.type == Light::SPOT) - { - it.location = it.location * viewMatrix; - it.direction = (viewMatrix * it.lookAt - it.location * viewMatrix); - } - } - } }; \ No newline at end of file diff --git a/BaseGLProject/Source.cpp b/BaseGLProject/Source.cpp index 07e5245..e19a9a5 100644 --- a/BaseGLProject/Source.cpp +++ b/BaseGLProject/Source.cpp @@ -18,6 +18,8 @@ double cx, cy; int g_width; int g_height; +bool reset = false; + void window_size_callback(GLFWwindow* window, int width, int height) { g_width = width; @@ -25,9 +27,11 @@ void window_size_callback(GLFWwindow* window, int width, int height) } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) -{ +{ if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); + if (key == GLFW_KEY_R && action == GLFW_PRESS) + reset = true; } static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) @@ -159,8 +163,7 @@ void FPSDisplay(int width) { static int frameCount = 0; static int fps = 60; - static double previousTime = glfwGetTime(); - + static double previousTime = glfwGetTime(); double currentTime = glfwGetTime(); frameCount++; // If a second has passed. @@ -215,9 +218,9 @@ int loop(GLFWwindow *window) MyGlWindow glWin(width, heigth); glWin.scnctx.fboDisplayName = "position_buffer"; - bool is_selected = false; + bool is_selected = false; - glWin.scnctx.renderMode = GBUF_DEBUG; + glWin.scnctx.renderMode = DEFERRED_LIGHT; glWin.scnctx.firstRedraw = true; std::vector lights_strs; @@ -225,8 +228,17 @@ int loop(GLFWwindow *window) int current_light = 0; + bool orbiting_lights = true; + float light_speed = 50.0f; + + double prev_time = glfwGetTime(); + double sinceLastFrame; + while (!glfwWindowShouldClose(window)) { + sinceLastFrame = glfwGetTime() - prev_time; + prev_time = glfwGetTime(); + ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); @@ -269,10 +281,26 @@ int loop(GLFWwindow *window) ImGui::EndCombo(); } + if (ImGui::BeginCombo("Scene Choice", + (glWin.scene == MOUNTAIN) ? "Mountain" : "Cubes")) + { + if (ImGui::Selectable("Mountain", &is_selected, 0, ImVec2(100, 10))) + glWin.loadScene(SceneChoice::MOUNTAIN); + if (ImGui::Selectable("Cubes", &is_selected, 0, ImVec2(100, 10))) + glWin.loadScene(SceneChoice::CUBES); + ImGui::EndCombo(); + } + ImGui::SetWindowPos(ImVec2(20, 20)); } ImGui::End(); + if (reset) + { + glWin.loadScene(SceneChoice::MOUNTAIN); + reset = false; + } + if (ImGui::Begin("Light management")) { lights_strs.clear(); @@ -297,7 +325,18 @@ int loop(GLFWwindow *window) && glWin.scnctx.renderMode == DEFERRED_LIGHT) glWin.multipassManager.recomputeDeferredLights(glWin.scnctx); + if (ImGui::SliderFloat("Selected light R", &glWin.scnctx.lights[current_light].intensity.x, 0, 1) + && glWin.scnctx.renderMode == DEFERRED_LIGHT) + glWin.multipassManager.recomputeDeferredLights(glWin.scnctx); + if (ImGui::SliderFloat("Selected light G", &glWin.scnctx.lights[current_light].intensity.y, 0, 1) + && glWin.scnctx.renderMode == DEFERRED_LIGHT) + glWin.multipassManager.recomputeDeferredLights(glWin.scnctx); + if (ImGui::SliderFloat("Selected light B", &glWin.scnctx.lights[current_light].intensity.z, 0, 1) + && glWin.scnctx.renderMode == DEFERRED_LIGHT) + glWin.multipassManager.recomputeDeferredLights(glWin.scnctx); + ImGui::Checkbox("Orbit Lights", &orbiting_lights); + ImGui::SliderFloat("Orbit degrees / second", &light_speed, 0, 360); } ImGui::End(); @@ -305,6 +344,8 @@ int loop(GLFWwindow *window) glfwSwapBuffers(window); glWin.draw(); + if (orbiting_lights) + glWin.orbitLights(sinceLastFrame, light_speed); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); diff --git a/BaseGLProject/imgui.ini b/BaseGLProject/imgui.ini index aff7282..640d8fc 100644 --- a/BaseGLProject/imgui.ini +++ b/BaseGLProject/imgui.ini @@ -55,7 +55,7 @@ Collapsed=0 [Window][Scene settings] Pos=20,20 -Size=309,85 +Size=314,106 Collapsed=0 [Window][FPSCounterOutline] @@ -84,7 +84,7 @@ Size=32,32 Collapsed=0 [Window][Light management] -Pos=12,120 -Size=410,449 +Pos=11,173 +Size=443,328 Collapsed=0