实现弹簧

main
wuyize 2023-04-19 20:38:30 +08:00
parent 588bfecd65
commit 5bd6647d14
8 changed files with 103 additions and 9 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\PhysicsManager.h" />
<ClInclude Include="src\RenderPass.h" /> <ClInclude Include="src\RenderPass.h" />
<ClInclude Include="src\RenderPassContext.h" /> <ClInclude Include="src\RenderPassContext.h" />
<ClInclude Include="src\Shader.h" /> <ClInclude Include="src\Shader.h" />
@ -51,6 +52,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\PhysicsManager.cpp" />
<ClCompile Include="src\RenderPass.cpp" /> <ClCompile Include="src\RenderPass.cpp" />
<ClCompile Include="src\Shader.cpp" /> <ClCompile Include="src\Shader.cpp" />
<ClCompile Include="src\World.cpp" /> <ClCompile Include="src\World.cpp" />

View File

@ -22,12 +22,26 @@ DemoWorld::DemoWorld()
sponza->setScale(glm::vec3(2)); sponza->setScale(glm::vec3(2));
auto particle = std::make_shared<Particle>(10); auto particle = std::make_shared<Particle>(10);
particle->setSpeed(glm::vec3(-1, 0, 0));
particle->setPosition({ 4, 5, 0 }); particle->setPosition({ 4, 5, 0 });
particle->addForce(std::make_shared<Force>(glm::vec3(0.f, -particle->getMass() * 9.8f, 0.f))); //particle->addForce(std::make_shared<Force>(glm::vec3(0.f, -particle->getMass() * 9.8f, 0.f)));
auto particle2 = std::make_shared<Particle>(10, "Models/vampire/vampire.gltf");
particle2->setSpeed(glm::vec3(1, 0, 0));
particle2->setPosition({ 6, 5, 0 });
particle2->setScale(glm::vec3{ 0.4 });
auto particle3 = std::make_shared<Particle>(10);
particle3->setSpeed(glm::vec3(0, 1, 0));
particle3->setPosition({ 6, 7, 0 });
physicsManager.addSpring(particle, particle2, 2, 10, 0);
physicsManager.addSpring(particle2, particle3, 2, 10, 0);
addActor(actor); addActor(actor);
addActor(actor2); addActor(actor2);
addActor(actor3); addActor(actor3);
addActor(sponza); addActor(sponza);
addActor(particle); addActor(particle);
addActor(particle2);
addActor(particle3);
} }

View File

@ -7,17 +7,28 @@ Particle::Particle(float mass)
, debugShader(gl, "Shaders/debug.vert", "Shaders/debug.frag") , debugShader(gl, "Shaders/debug.vert", "Shaders/debug.frag")
{ {
model = Model::createSphere(gl); model = Model::createSphere(gl);
setScale(glm::vec3(0.4)); setScale(glm::vec3(0.2));
}
Particle::Particle(float mass, const std::string& path)
: Actor(path)
, mass(mass)
, debugShader(gl, "Shaders/debug.vert", "Shaders/debug.frag")
{
} }
void Particle::logicalTick(float deltaTime) void Particle::logicalTick(float deltaTime)
{ {
resultantForce = glm::vec3(0);
for (auto& force : forces)
resultantForce += force->value;
auto pos = getPosition() + speed * deltaTime + 0.5f * resultantForce / mass * deltaTime * deltaTime; auto pos = getPosition() + speed * deltaTime + 0.5f * resultantForce / mass * deltaTime * deltaTime;
speed += resultantForce / mass * deltaTime; speed += resultantForce / mass * deltaTime;
if (speed.y < 0 && pos.y < 0.4) //if (speed.y < 0 && pos.y < 0.4)
{ //{
speed.y = -speed.y; // speed.y = -speed.y;
} //}
setPosition(pos); setPosition(pos);
} }
@ -48,7 +59,7 @@ void Particle::draw(const RenderPassContext& context, Shader& shader)
debugShader.use(); debugShader.use();
debugShader.setUniformValue("projection", *context.projection); debugShader.setUniformValue("projection", *context.projection);
debugShader.setUniformValue("view", *context.view); debugShader.setUniformValue("view", *context.view);
glm::mat4 modelMatrix = glm::translate(glm::mat4(1), getPosition()) * glm::scale(glm::mat4(1), getScale()) * glm::mat4_cast(getRotation()); glm::mat4 modelMatrix = glm::translate(glm::mat4(1), getPosition()) * glm::scale(glm::mat4(1), getScale()) * glm::mat4_cast(getRotation()) * glm::scale(glm::mat4(1), glm::vec3(glm::abs(resultantForce / mass)));
gl->BindVertexArray(vao); gl->BindVertexArray(vao);
for (auto& force : forces) for (auto& force : forces)
{ {
@ -64,16 +75,24 @@ void Particle::draw(const RenderPassContext& context, Shader& shader)
void Particle::addForce(std::shared_ptr<Force> force) void Particle::addForce(std::shared_ptr<Force> force)
{ {
forces.insert(force); forces.insert(force);
resultantForce += force->value;
} }
void Particle::removeForce(std::shared_ptr<Force> force) void Particle::removeForce(std::shared_ptr<Force> force)
{ {
forces.erase(force); forces.erase(force);
resultantForce -= force->value;
} }
float Particle::getMass() float Particle::getMass()
{ {
return mass; return mass;
} }
glm::vec3 Particle::getSpeed()
{
return speed;
}
void Particle::setSpeed(const glm::vec3& speed)
{
this->speed = speed;
}

View File

@ -12,12 +12,15 @@ class Particle : public Actor
{ {
public: public:
Particle(float mass); Particle(float mass);
Particle(float mass, const std::string& path);
virtual ~Particle() = default; virtual ~Particle() = default;
virtual void logicalTick(float deltaTime); virtual void logicalTick(float deltaTime);
virtual void draw(const RenderPassContext& context, Shader& shader); virtual void draw(const RenderPassContext& context, Shader& shader);
void addForce(std::shared_ptr<Force> force); void addForce(std::shared_ptr<Force> force);
void removeForce(std::shared_ptr<Force> force); void removeForce(std::shared_ptr<Force> force);
float getMass(); float getMass();
glm::vec3 getSpeed();
void setSpeed(const glm::vec3& speed);
private: private:
float mass; float mass;
glm::vec3 speed = glm::vec3(0.f); glm::vec3 speed = glm::vec3(0.f);

View File

@ -0,0 +1,30 @@
#include "PhysicsManager.h"
void PhysicsManager::tick(float deltaTime)
{
for (auto iter = constraints.begin(); iter < constraints.end(); )
{
if (iter->p1.expired() || iter->p2.expired())
iter = constraints.erase(iter);
else
{
iter->f1->value = iter->solver(*iter->p1.lock(), *iter->p2.lock());
iter->f2->value = -iter->f1->value;
iter++;
}
}
}
void PhysicsManager::addSpring(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;
return -(ks * (d - length) + kd * vd) * (p1.getPosition() - p2.getPosition()) / d;
}, f1, f2);
}

View File

@ -0,0 +1,22 @@
#pragma once
#include "Particle.h"
struct BinaryConstraint
{
std::weak_ptr<Particle> p1;
std::weak_ptr<Particle> p2;
std::function<glm::vec3(Particle& p1, Particle& p2)> solver; /// f1
std::shared_ptr<Force> f1;
std::shared_ptr<Force> f2;
};
class PhysicsManager
{
public:
void tick(float deltaTime);
void addSpring(std::shared_ptr<Particle> p1, std::shared_ptr<Particle> p2, float length, float ks, float kd);
private:
std::vector<BinaryConstraint> constraints;
};

View File

@ -2,6 +2,7 @@
void World::logicalTick(float deltaTime) void World::logicalTick(float deltaTime)
{ {
physicsManager.tick(deltaTime);
for (auto& actor : actors) for (auto& actor : actors)
actor->logicalTick(deltaTime); actor->logicalTick(deltaTime);
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "Actor.h" #include "Actor.h"
#include "RenderPassContext.h" #include "RenderPassContext.h"
#include "PhysicsManager.h"
class World class World
{ {
@ -11,5 +12,7 @@ public:
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);
std::pair<glm::vec3, glm::vec3> getAABB(); std::pair<glm::vec3, glm::vec3> getAABB();
protected:
PhysicsManager physicsManager;
}; };