实现橡皮筋和引力

main
wuyize 2023-06-02 15:07:13 +08:00
parent 7ca74a245d
commit 5a4bd74ba0
14 changed files with 248 additions and 12 deletions

View File

@ -31,6 +31,7 @@
<ClInclude Include="src\Mesh.h" /> <ClInclude Include="src\Mesh.h" />
<ClInclude Include="src\Model.h" /> <ClInclude Include="src\Model.h" />
<ClInclude Include="src\Particle.h" /> <ClInclude Include="src\Particle.h" />
<ClInclude Include="src\ParticleWorld.h" />
<ClInclude Include="src\PhysicsManager.h" /> <ClInclude Include="src\PhysicsManager.h" />
<ClInclude Include="src\RenderingSystem.h" /> <ClInclude Include="src\RenderingSystem.h" />
<ClInclude Include="src\RenderPass.h" /> <ClInclude Include="src\RenderPass.h" />
@ -53,6 +54,7 @@
<ClCompile Include="src\Mesh.cpp" /> <ClCompile Include="src\Mesh.cpp" />
<ClCompile Include="src\Model.cpp" /> <ClCompile Include="src\Model.cpp" />
<ClCompile Include="src\Particle.cpp" /> <ClCompile Include="src\Particle.cpp" />
<ClCompile Include="src\ParticleWorld.cpp" />
<ClCompile Include="src\PhysicsManager.cpp" /> <ClCompile Include="src\PhysicsManager.cpp" />
<ClCompile Include="src\RenderingSystem.cpp" /> <ClCompile Include="src\RenderingSystem.cpp" />
<ClCompile Include="src\RenderPass.cpp" /> <ClCompile Include="src\RenderPass.cpp" />

View File

@ -72,6 +72,9 @@
<ClInclude Include="src\RenderingSystem.h"> <ClInclude Include="src\RenderingSystem.h">
<Filter>头文件</Filter> <Filter>头文件</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\ParticleWorld.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="src\gl.c"> <ClCompile Include="src\gl.c">
@ -131,6 +134,9 @@
<ClCompile Include="src\RenderingSystem.cpp"> <ClCompile Include="src\RenderingSystem.cpp">
<Filter>源文件</Filter> <Filter>源文件</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\ParticleWorld.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Shaders\brdf_lut.comp"> <None Include="Shaders\brdf_lut.comp">

View File

@ -114,7 +114,7 @@ void DemoWorld::rendererTick(float deltaTime)
World::rendererTick(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 bool firstMouse = true;
static float lastX; static float lastX;

View File

@ -7,7 +7,7 @@ public:
DemoWorld(); DemoWorld();
void logicalTick(float deltaTime) override; void logicalTick(float deltaTime) override;
void rendererTick(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 scrollCallback(GLFWwindow* window, double xoffset, double yoffset) override;
virtual void processInput(GLFWwindow* window, float deltaTime) override; virtual void processInput(GLFWwindow* window, float deltaTime) override;

View File

@ -243,7 +243,7 @@ GLuint IblUtils::generateCubemap(GladGLContext* gl, GLuint captureFBO, GLuint ca
// --------------------------------- // ---------------------------------
stbi_set_flip_vertically_on_load(true); stbi_set_flip_vertically_on_load(true);
int width, height, nrComponents; 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; unsigned int hdrTexture = 0;
if (data) if (data)
{ {

View File

@ -7,6 +7,7 @@ struct GladGLContext;
class IblUtils class IblUtils
{ {
public: public:
static constexpr char hdrPath[] = "HDRI/clarens_midday_4k.hdr";
static constexpr int cubemapSize = 1024; static constexpr int cubemapSize = 1024;
static constexpr int irradianceMapSize = 32; static constexpr int irradianceMapSize = 32;
static constexpr int prefilterMapSize = 128; static constexpr int prefilterMapSize = 128;

View File

@ -1,6 +1,7 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "Particle.h" #include "Particle.h"
#include "DemoWorld.h" #include "DemoWorld.h"
#include "ParticleWorld.h"
#include "RenderingSystem.h" #include "RenderingSystem.h"
@ -23,7 +24,10 @@ int MainWindow::exec()
RenderingSystem::instance().framebufferSizeCallback(window, width, height); RenderingSystem::instance().framebufferSizeCallback(window, width, height);
}); });
glfwSetCursorPosCallback(window, [](GLFWwindow* window, double xpos, double ypos) { 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) { glfwSetScrollCallback(window, [](GLFWwindow* window, double xoffset, double yoffset) {
MainWindow::instance().scrollCallback(window, xoffset, yoffset); MainWindow::instance().scrollCallback(window, xoffset, yoffset);
@ -43,7 +47,7 @@ int MainWindow::exec()
} }
world = std::make_unique<DemoWorld>(); world = std::make_unique<ParticleWorld>();
auto [minPos, maxPos] = world->getAABB(); auto [minPos, maxPos] = world->getAABB();
std::cout << std::format("{},{},{} {},{},{}\n", minPos.x, minPos.y, minPos.z, maxPos.x, maxPos.y, maxPos.z); 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); 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) void MainWindow::scrollCallback(GLFWwindow* window, double xoffset, double yoffset)

View File

@ -15,7 +15,8 @@ public:
private: private:
MainWindow(); 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 scrollCallback(GLFWwindow* window, double xoffset, double yoffset);
void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
void processInput(GLFWwindow* window, float deltaTime); void processInput(GLFWwindow* window, float deltaTime);

View File

@ -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<Particle>(1);
p0->setPosition({ 0,1,0 });
p0->setFixed(true);
auto p1 = std::make_shared<Particle>(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<Particle>(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<Particle>(100);
planet->setPosition({ -10,0,0 });
planet->setFixed(true);
auto p1 = std::make_shared<Particle>(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<Particle>(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<double>());
else if (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS)
lightYaw = glm::mod(lightYaw + yoffset / 100., 2 * glm::pi<double>());
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);
}

View File

@ -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<std::shared_ptr<Particle>> particles;
std::shared_ptr<Particle> 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;
};

View File

@ -5,7 +5,11 @@ void PhysicsManager::tick(float deltaTime)
for (auto iter = constraints.begin(); iter < constraints.end(); ) for (auto iter = constraints.begin(); iter < constraints.end(); )
{ {
if (iter->p1.expired() || iter->p2.expired()) 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); iter = constraints.erase(iter);
}
else else
{ {
iter->f1->value = iter->solver(*iter->p1.lock(), *iter->p2.lock()); iter->f1->value = iter->solver(*iter->p1.lock(), *iter->p2.lock());
@ -29,3 +33,33 @@ void PhysicsManager::addSpring(std::shared_ptr<Particle> p1, std::shared_ptr<Par
return -(ks * (d - length) + kd * vd) * (p1.getPosition() - p2.getPosition()) / d; return -(ks * (d - length) + kd * vd) * (p1.getPosition() - p2.getPosition()) / d;
}, f1, f2); }, f1, f2);
} }
void PhysicsManager::addRubberBand(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float length, float ks, float kd)
{
auto f1 = std::make_shared<Force>(glm::vec3(0));
auto f2 = std::make_shared<Force>(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<Particle> p1, std::shared_ptr<Particle> p2, float G)
{
auto f1 = std::make_shared<Force>(glm::vec3(0));
auto f2 = std::make_shared<Force>(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);
}

View File

@ -15,6 +15,8 @@ class PhysicsManager
public: public:
void tick(float deltaTime); void tick(float deltaTime);
void addSpring(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float length, float ks, float kd); void addSpring(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float length, float ks, float kd);
void addRubberBand(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float length, float ks, float kd);
void addGravitation(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float G = 6.67430e-11f);
private: private:
std::vector<BinaryConstraint> constraints; std::vector<BinaryConstraint> constraints;

View File

@ -27,7 +27,12 @@ void World::draw(const RenderPassContext& context, Shader& shader)
void World::addActor(std::shared_ptr<Actor> actor) void World::addActor(std::shared_ptr<Actor> actor)
{ {
actors.push_back(actor); actors.insert(actor);
}
void World::removeActor(std::shared_ptr<Actor> actor)
{
actors.erase(actor);
} }
std::pair<glm::vec3, glm::vec3> World::getAABB() std::pair<glm::vec3, glm::vec3> World::getAABB()
@ -41,4 +46,4 @@ std::pair<glm::vec3, glm::vec3> World::getAABB()
maxPos = glm::max(maxPos, max); maxPos = glm::max(maxPos, max);
} }
return { minPos, maxPos }; return { minPos, maxPos };
} }

View File

@ -11,15 +11,17 @@ class World
public: public:
Camera camera; Camera camera;
Light light; Light light;
std::vector<std::shared_ptr<Actor>> actors; std::set<std::shared_ptr<Actor>> actors;
World(); World();
virtual void logicalTick(float deltaTime); virtual void logicalTick(float deltaTime);
virtual void rendererTick(float deltaTime); virtual void rendererTick(float deltaTime);
void draw(const RenderPassContext& context, Shader& shader); void draw(const RenderPassContext& context, Shader& shader);
void addActor(std::shared_ptr<Actor> actor); void addActor(std::shared_ptr<Actor> actor);
void removeActor(std::shared_ptr<Actor> actor);
std::pair<glm::vec3, glm::vec3> getAABB(); std::pair<glm::vec3, glm::vec3> 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 scrollCallback(GLFWwindow* window, double xoffset, double yoffset) {};
virtual void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {}; virtual void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {};
virtual void processInput(GLFWwindow* window, float deltaTime) {}; virtual void processInput(GLFWwindow* window, float deltaTime) {};