From 5a4bd74ba046367ceef7b28f3bb7524e9ad95a0b Mon Sep 17 00:00:00 2001 From: wuyize Date: Fri, 2 Jun 2023 15:07:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=A9=A1=E7=9A=AE=E7=AD=8B?= =?UTF-8?q?=E5=92=8C=E5=BC=95=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ToyEngine/ToyEngine.vcxproj | 2 + ToyEngine/ToyEngine.vcxproj.filters | 6 ++ ToyEngine/src/DemoWorld.cpp | 2 +- ToyEngine/src/DemoWorld.h | 2 +- ToyEngine/src/IblUtils.cpp | 2 +- ToyEngine/src/IblUtils.h | 1 + ToyEngine/src/MainWindow.cpp | 17 +++- ToyEngine/src/MainWindow.h | 3 +- ToyEngine/src/ParticleWorld.cpp | 149 ++++++++++++++++++++++++++++ ToyEngine/src/ParticleWorld.h | 25 +++++ ToyEngine/src/PhysicsManager.cpp | 34 +++++++ ToyEngine/src/PhysicsManager.h | 2 + ToyEngine/src/World.cpp | 9 +- ToyEngine/src/World.h | 6 +- 14 files changed, 248 insertions(+), 12 deletions(-) create mode 100644 ToyEngine/src/ParticleWorld.cpp create mode 100644 ToyEngine/src/ParticleWorld.h diff --git a/ToyEngine/ToyEngine.vcxproj b/ToyEngine/ToyEngine.vcxproj index dced617..a72d952 100644 --- a/ToyEngine/ToyEngine.vcxproj +++ b/ToyEngine/ToyEngine.vcxproj @@ -31,6 +31,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/ToyEngine/ToyEngine.vcxproj.filters b/ToyEngine/ToyEngine.vcxproj.filters index 161e55d..688fc93 100644 --- a/ToyEngine/ToyEngine.vcxproj.filters +++ b/ToyEngine/ToyEngine.vcxproj.filters @@ -72,6 +72,9 @@ 头文件 + + 头文件 + @@ -131,6 +134,9 @@ 源文件 + + 源文件 + diff --git a/ToyEngine/src/DemoWorld.cpp b/ToyEngine/src/DemoWorld.cpp index c469d66..2ab9f11 100644 --- a/ToyEngine/src/DemoWorld.cpp +++ b/ToyEngine/src/DemoWorld.cpp @@ -114,7 +114,7 @@ void DemoWorld::rendererTick(float deltaTime) World::rendererTick(deltaTime); } -void DemoWorld::mouseCallback(GLFWwindow* window, double xpos, double ypos) +void DemoWorld::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { static bool firstMouse = true; static float lastX; diff --git a/ToyEngine/src/DemoWorld.h b/ToyEngine/src/DemoWorld.h index a9d0128..05888e1 100644 --- a/ToyEngine/src/DemoWorld.h +++ b/ToyEngine/src/DemoWorld.h @@ -7,7 +7,7 @@ public: DemoWorld(); void logicalTick(float deltaTime) override; void rendererTick(float deltaTime) override; - virtual void mouseCallback(GLFWwindow* window, double xpos, double ypos) override; + virtual void cursorPosCallback(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; diff --git a/ToyEngine/src/IblUtils.cpp b/ToyEngine/src/IblUtils.cpp index 5d5695c..45f9272 100644 --- a/ToyEngine/src/IblUtils.cpp +++ b/ToyEngine/src/IblUtils.cpp @@ -243,7 +243,7 @@ GLuint IblUtils::generateCubemap(GladGLContext* gl, GLuint captureFBO, GLuint ca // --------------------------------- stbi_set_flip_vertically_on_load(true); int width, height, nrComponents; - float* data = stbi_loadf("HDRI/clarens_midday_4k.hdr", &width, &height, &nrComponents, 0); + float* data = stbi_loadf(hdrPath, &width, &height, &nrComponents, 0); unsigned int hdrTexture = 0; if (data) { diff --git a/ToyEngine/src/IblUtils.h b/ToyEngine/src/IblUtils.h index c91a6ad..53063b8 100644 --- a/ToyEngine/src/IblUtils.h +++ b/ToyEngine/src/IblUtils.h @@ -7,6 +7,7 @@ struct GladGLContext; class IblUtils { public: + static constexpr char hdrPath[] = "HDRI/clarens_midday_4k.hdr"; static constexpr int cubemapSize = 1024; static constexpr int irradianceMapSize = 32; static constexpr int prefilterMapSize = 128; diff --git a/ToyEngine/src/MainWindow.cpp b/ToyEngine/src/MainWindow.cpp index b3110d7..4656b24 100644 --- a/ToyEngine/src/MainWindow.cpp +++ b/ToyEngine/src/MainWindow.cpp @@ -1,6 +1,7 @@ #include "MainWindow.h" #include "Particle.h" #include "DemoWorld.h" +#include "ParticleWorld.h" #include "RenderingSystem.h" @@ -23,7 +24,10 @@ int MainWindow::exec() RenderingSystem::instance().framebufferSizeCallback(window, width, height); }); glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) { - MainWindow::instance().mouseCallback(window, xpos, ypos); + MainWindow::instance().cursorPosCallback(window, xpos, ypos); + }); + glfwSetMouseButtonCallback(window, [](GLFWwindow* window, int button, int action, int mods) { + MainWindow::instance().mouseButtonCallback(window, button, action, mods); }); glfwSetScrollCallback(window, [](GLFWwindow* window, double xoffset, double yoffset) { MainWindow::instance().scrollCallback(window, xoffset, yoffset); @@ -43,7 +47,7 @@ int MainWindow::exec() } - 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); @@ -113,9 +117,14 @@ void MainWindow::processInput(GLFWwindow* window, float deltaTime) world->processInput(window, deltaTime); } -void MainWindow::mouseCallback(GLFWwindow* window, double xpos, double ypos) +void MainWindow::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { - world->mouseCallback(window, xpos, ypos); + world->cursorPosCallback(window, xpos, ypos); +} + +void MainWindow::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + world->mouseButtonCallback(window, button, action, mods); } void MainWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) diff --git a/ToyEngine/src/MainWindow.h b/ToyEngine/src/MainWindow.h index 4bd891e..85ca002 100644 --- a/ToyEngine/src/MainWindow.h +++ b/ToyEngine/src/MainWindow.h @@ -15,7 +15,8 @@ public: private: MainWindow(); - void mouseCallback(GLFWwindow* window, double xpos, double ypos); + void cursorPosCallback(GLFWwindow* window, double xpos, double ypos); + void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void scrollCallback(GLFWwindow* window, double xoffset, double yoffset); void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); void processInput(GLFWwindow* window, float deltaTime); diff --git a/ToyEngine/src/ParticleWorld.cpp b/ToyEngine/src/ParticleWorld.cpp new file mode 100644 index 0000000..b0d7d57 --- /dev/null +++ b/ToyEngine/src/ParticleWorld.cpp @@ -0,0 +1,149 @@ +#include "ParticleWorld.h" +#include "Particle.h" +#include "RenderingSystem.h" + +ParticleWorld::ParticleWorld() +{ + light.lightDirection = glm::normalize(glm::vec3((cos(lightPitch) * cos(lightYaw)), (sin(lightPitch)), (cos(lightPitch) * sin(lightYaw)))); + light.radiance = 15.f * lightColor; + + { + auto p0 = std::make_shared(1); + p0->setPosition({ 0,1,0 }); + p0->setFixed(true); + + auto p1 = std::make_shared(1); + p1->setPosition({ 0,0,0 }); + p1->setEnableGravity(true); + + addActor(p0); + addActor(p1); + + physicsManager.addSpring(p0, p1, 2, 5, 0.1); + } + + for (int i = 0, particleCount = 5; i < particleCount; i++) + { + auto particle = std::make_shared(1); + particle->setPosition({ 5, 0, glm::mix(-3.1f,2.f,(double)i / (particleCount - 1)) }); + if (i == 0 || i == particleCount - 1) + particle->setFixed(true); + else + particle->setEnableGravity(true); + + particles.push_back(particle); + addActor(particle); + + if (i != 0) + { + float ks = 10, kd = 0.1; + physicsManager.addRubberBand(particles[i - 1], particle, 0.01, ks, kd); + } + } + + { + planet = std::make_shared(100); + planet->setPosition({ -10,0,0 }); + planet->setFixed(true); + + auto p1 = std::make_shared(1); + p1->setPosition({ -15,0,0 }); + p1->setSpeed(glm::vec3(0, 0, 1) * glm::sqrt(G * planet->getMass() / glm::distance(planet->getPosition(), p1->getPosition()))); + + addActor(planet); + addActor(p1); + + physicsManager.addGravitation(planet, p1, G); + } +} + +void ParticleWorld::logicalTick(float deltaTime) +{ + World::logicalTick(deltaTime); +} + +void ParticleWorld::rendererTick(float deltaTime) +{ + World::rendererTick(deltaTime); + + for (auto iter = particles.begin(); iter != particles.end(); ) + { + if (glm::length2((*iter)->getPosition()) > 1e4) + { + removeActor(*iter); + iter = particles.erase(iter); + } + else iter++; + } + + if (addNewParticle) + { + addNewParticle = false; + + auto p = std::make_shared(1); + p->setPosition(camera.Position + glm::vec3(0, -0.3, 0)); + p->setSpeed(5.f * glm::normalize(camera.Front)); + addActor(p); + physicsManager.addGravitation(planet, p, G); + particles.push_back(p); + } +} + +void ParticleWorld::cursorPosCallback(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 ParticleWorld::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +{ + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) + addNewParticle = true; +} + +void ParticleWorld::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 ParticleWorld::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/ParticleWorld.h b/ToyEngine/src/ParticleWorld.h new file mode 100644 index 0000000..051b6c4 --- /dev/null +++ b/ToyEngine/src/ParticleWorld.h @@ -0,0 +1,25 @@ +#pragma once +#include "World.h" +class ParticleWorld : public World +{ +public: + ParticleWorld(); + void logicalTick(float deltaTime) override; + void rendererTick(float deltaTime) override; + virtual void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) override; + virtual void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) 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 planet; + float G = 1; + + 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); + + bool addNewParticle = false; +}; + diff --git a/ToyEngine/src/PhysicsManager.cpp b/ToyEngine/src/PhysicsManager.cpp index 996f040..50cc659 100644 --- a/ToyEngine/src/PhysicsManager.cpp +++ b/ToyEngine/src/PhysicsManager.cpp @@ -5,7 +5,11 @@ void PhysicsManager::tick(float deltaTime) for (auto iter = constraints.begin(); iter < constraints.end(); ) { if (iter->p1.expired() || iter->p2.expired()) + { + if (!iter->p1.expired()) iter->p1.lock()->removeForce(iter->f1); + if (!iter->p2.expired()) iter->p2.lock()->removeForce(iter->f2); iter = constraints.erase(iter); + } else { iter->f1->value = iter->solver(*iter->p1.lock(), *iter->p2.lock()); @@ -29,3 +33,33 @@ void PhysicsManager::addSpring(std::shared_ptr p1, std::shared_ptr p1, std::shared_ptr p2, float length, float ks, float kd) +{ + auto f1 = std::make_shared(glm::vec3(0)); + auto f2 = std::make_shared(glm::vec3(0)); + p1->addForce(f1); + p2->addForce(f2); + constraints.emplace_back(p1, p2, [length, ks, kd](Particle& p1, Particle& p2) { + auto d = glm::distance(p1.getPosition(), p2.getPosition()); + float dt = 1.f; + auto vd = glm::distance(p1.getPosition() + p1.getSpeed() * dt, p2.getPosition() + p2.getSpeed() * dt) / dt; + if (d <= length) return glm::vec3(0); + return -(ks * (d - length) + kd * vd) * (p1.getPosition() - p2.getPosition()) / d; + }, f1, f2); +} + +void PhysicsManager::addGravitation(std::shared_ptr p1, std::shared_ptr p2, float G) +{ + auto f1 = std::make_shared(glm::vec3(0)); + auto f2 = std::make_shared(glm::vec3(0)); + p1->addForce(f1); + p2->addForce(f2); + constraints.emplace_back(p1, p2, [G](Particle& p1, Particle& p2) { + auto D = p2.getPosition() - p1.getPosition(); + auto d2 = glm::length2(D); + auto d = glm::sqrt(d2); + if (d <= 1e-5) return glm::vec3(0); + return G * p1.getMass() * p2.getMass() / d2 * D / d; + }, f1, f2); +} diff --git a/ToyEngine/src/PhysicsManager.h b/ToyEngine/src/PhysicsManager.h index 3190172..3c4aa1d 100644 --- a/ToyEngine/src/PhysicsManager.h +++ b/ToyEngine/src/PhysicsManager.h @@ -15,6 +15,8 @@ class PhysicsManager public: void tick(float deltaTime); void addSpring(std::shared_ptr p1, std::shared_ptr p2, float length, float ks, float kd); + void addRubberBand(std::shared_ptr p1, std::shared_ptr p2, float length, float ks, float kd); + void addGravitation(std::shared_ptr p1, std::shared_ptr p2, float G = 6.67430e-11f); private: std::vector constraints; diff --git a/ToyEngine/src/World.cpp b/ToyEngine/src/World.cpp index 87b5959..4f66902 100644 --- a/ToyEngine/src/World.cpp +++ b/ToyEngine/src/World.cpp @@ -27,7 +27,12 @@ void World::draw(const RenderPassContext& context, Shader& shader) void World::addActor(std::shared_ptr actor) { - actors.push_back(actor); + actors.insert(actor); +} + +void World::removeActor(std::shared_ptr actor) +{ + actors.erase(actor); } std::pair World::getAABB() @@ -41,4 +46,4 @@ std::pair World::getAABB() maxPos = glm::max(maxPos, max); } return { minPos, maxPos }; -} \ No newline at end of file +} diff --git a/ToyEngine/src/World.h b/ToyEngine/src/World.h index f2bec0c..4c4340a 100644 --- a/ToyEngine/src/World.h +++ b/ToyEngine/src/World.h @@ -11,15 +11,17 @@ class World public: Camera camera; Light light; - std::vector> actors; + std::set> 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); + void removeActor(std::shared_ptr actor); std::pair getAABB(); - virtual void mouseCallback(GLFWwindow* window, double xpos, double ypos) {}; + virtual void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) {}; + virtual void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {}; 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) {};