实现橡皮筋和引力
parent
7ca74a245d
commit
5a4bd74ba0
|
@ -31,6 +31,7 @@
|
|||
<ClInclude Include="src\Mesh.h" />
|
||||
<ClInclude Include="src\Model.h" />
|
||||
<ClInclude Include="src\Particle.h" />
|
||||
<ClInclude Include="src\ParticleWorld.h" />
|
||||
<ClInclude Include="src\PhysicsManager.h" />
|
||||
<ClInclude Include="src\RenderingSystem.h" />
|
||||
<ClInclude Include="src\RenderPass.h" />
|
||||
|
@ -53,6 +54,7 @@
|
|||
<ClCompile Include="src\Mesh.cpp" />
|
||||
<ClCompile Include="src\Model.cpp" />
|
||||
<ClCompile Include="src\Particle.cpp" />
|
||||
<ClCompile Include="src\ParticleWorld.cpp" />
|
||||
<ClCompile Include="src\PhysicsManager.cpp" />
|
||||
<ClCompile Include="src\RenderingSystem.cpp" />
|
||||
<ClCompile Include="src\RenderPass.cpp" />
|
||||
|
|
|
@ -72,6 +72,9 @@
|
|||
<ClInclude Include="src\RenderingSystem.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\ParticleWorld.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\gl.c">
|
||||
|
@ -131,6 +134,9 @@
|
|||
<ClCompile Include="src\RenderingSystem.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ParticleWorld.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Shaders\brdf_lut.comp">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DemoWorld>();
|
||||
world = std::make_unique<ParticleWorld>();
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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<Particle> p1, std::shared_ptr<Par
|
|||
return -(ks * (d - length) + kd * vd) * (p1.getPosition() - p2.getPosition()) / d;
|
||||
}, 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);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ 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);
|
||||
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:
|
||||
std::vector<BinaryConstraint> constraints;
|
||||
|
|
|
@ -27,7 +27,12 @@ void World::draw(const RenderPassContext& context, Shader& shader)
|
|||
|
||||
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()
|
||||
|
@ -41,4 +46,4 @@ std::pair<glm::vec3, glm::vec3> World::getAABB()
|
|||
maxPos = glm::max(maxPos, max);
|
||||
}
|
||||
return { minPos, maxPos };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,17 @@ class World
|
|||
public:
|
||||
Camera camera;
|
||||
Light light;
|
||||
std::vector<std::shared_ptr<Actor>> actors;
|
||||
std::set<std::shared_ptr<Actor>> 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> actor);
|
||||
void removeActor(std::shared_ptr<Actor> actor);
|
||||
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 keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {};
|
||||
virtual void processInput(GLFWwindow* window, float deltaTime) {};
|
||||
|
|
Loading…
Reference in New Issue