Physics Simulation & Visualization Tool 0.1
A C++ physics simulation engine with real-time 3D visualization
Loading...
Searching...
No Matches
RigidBody.cpp
Go to the documentation of this file.
1#include "RigidBody.h"
2
3#include <algorithm>
4#include <iostream>
5#include <glm/gtc/matrix_transform.hpp>
6
7#include "PointMass.h"
10
11namespace {
12constexpr double kContactAreaFraction = 0.01;
13constexpr double kContactConductionDistance = 0.01;
14}
15
16void Physics::RigidBody::setScale(const glm::vec3& newScale) {
17 std::lock_guard<std::mutex> lock(stateMutex);
18 scale = newScale;
19 recomputeGeometry();
20}
21
22void Physics::RigidBody::setGeometry(const std::vector<glm::vec3>& vertices, const std::vector<unsigned int>& indices) {
23 std::lock_guard<std::mutex> lock(stateMutex);
24 meshVertices = vertices;
25 meshIndices = indices;
26 recomputeGeometry();
27}
28
29void Physics::RigidBody::recomputeGeometry() {
30 if (meshIndices.empty()) return;
31 float area = 0.0f;
32
33 for (size_t i = 0; i < meshIndices.size(); i += 3) {
34 glm::vec3 a = meshVertices[meshIndices[i]] * scale;
35 glm::vec3 b = meshVertices[meshIndices[i+1]] * scale;
36 glm::vec3 c = meshVertices[meshIndices[i+2]] * scale;
37 area += 0.5f * glm::length(glm::cross(b - a, c - a));
38 }
39
40 surfaceArea = area;
41}
42
43Physics::RigidBody::RigidBody(uint32_t id, double m, std::unique_ptr<Bounding::ICollider> col, glm::vec3 pos, bool bodyStatic) : PhysicsBody(id) {
44 std::lock_guard<std::mutex> lock(stateMutex);
47 setWorldTransform(glm::translate(glm::mat4(1.0f), pos), BodyLock::NOLOCK);
48 collider = std::move(col);
49 setIsStatic(bodyStatic, BodyLock::NOLOCK);
50}
51
52Physics::RigidBody::RigidBody(uint32_t id, std::unique_ptr<Bounding::ICollider> col, glm::vec3 pos, bool bodyStatic) : PhysicsBody(id) {
53 std::lock_guard<std::mutex> lock(stateMutex);
54 collider = std::move(col);
55 setIsStatic(bodyStatic, BodyLock::NOLOCK);
57 setWorldTransform(glm::translate(glm::mat4(1.0f), pos), BodyLock::NOLOCK);
59}
60
62 std::unique_lock<std::mutex> maybeLock;
63 if (lock == BodyLock::LOCK)
64 maybeLock = std::unique_lock<std::mutex>(stateMutex);
65
66 frames.push_back( {this, t, getPosition(BodyLock::NOLOCK), getVelocity(BodyLock::NOLOCK), static_cast<float>(getThermalProperties(BodyLock::NOLOCK).tempK)} );
67}
68
70 std::unique_lock<std::mutex> maybeLock;
71 if (lock == BodyLock::LOCK)
72 maybeLock = std::unique_lock<std::mutex>(stateMutex);
73
74 setPosition(snapshot.position, BodyLock::NOLOCK);
75 setVelocity(snapshot.velocity, BodyLock::NOLOCK);
76 ThermalProperties props = getThermalProperties(BodyLock::NOLOCK);
77 props.tempK = snapshot.temperature;
78 setThermalProperty(props, BodyLock::NOLOCK);
79}
80
81void Physics::RigidBody::step(float dt, BodyLock lock) {
82 std::unique_lock<std::mutex> maybeLock;
83 if (lock == BodyLock::LOCK)
84 maybeLock = std::unique_lock<std::mutex>(stateMutex);
85
86 glm::vec3 acceleration = getNetForce(BodyLock::NOLOCK) / static_cast<float>(getMass(BodyLock::NOLOCK));
87 glm::vec3 posIncrement = getVelocity(BodyLock::NOLOCK) * dt + 0.5f * acceleration * dt * dt;
88 setPosition(getPosition(BodyLock::NOLOCK) + posIncrement, BodyLock::NOLOCK);
89 setWorldTransform(glm::translate(getWorldTransform(BodyLock::NOLOCK), posIncrement), BodyLock::NOLOCK);
90 glm::vec3 newAcceleration = getNetForce(BodyLock::NOLOCK) / static_cast<float>(getMass(BodyLock::NOLOCK)); // if netForce changed during the step
91 setVelocity(getVelocity(BodyLock::NOLOCK) + 0.5f * (acceleration + newAcceleration) * dt, BodyLock::NOLOCK);
92}
93
95 return other.collidesWithRigidBody(*this);
96}
97
99 glm::mat4 M = getWorldTransform(BodyLock::LOCK);
100 auto worldCollider = collider->getTransformed(M);
101 return worldCollider->contains(pm.getPosition(BodyLock::LOCK));
102}
103
105 return false;
106}
107
109 return other.resolveCollisionWithRigidBody(dt, *this);
110}
111
113 std::lock_guard<std::mutex> lock(stateMutex);
114 auto worldCollider = collider->getTransformed(getWorldTransform(BodyLock::NOLOCK));
115 Bounding::ContactInfo ci = worldCollider->closestPoint(pm.getPosition(BodyLock::NOLOCK));
116 if (ci.penetration < 0.0f) return false; // no overlap
117
118 float vRel = glm::dot(pm.getVelocity(BodyLock::NOLOCK), ci.normal);
119 if (vRel >= 0.0f) return false; // moving apart or resting
120
121 float e = 0.0f; // restitution coefficient
122 float j = -(1.0f + e) * vRel * static_cast<float>(pm.getMass(BodyLock::NOLOCK));
123
125 glm::vec3 Fnet(0.0f);
126 for (auto const& [n, f] : pm.getAllForces(BodyLock::NOLOCK)) Fnet += f;
127 glm::vec3 Fn = -glm::dot(Fnet, ci.normal) * ci.normal;
128
129 pm.setForce("Normal", Fn, BodyLock::NOLOCK);
131
132 // Friction heat & Contact conduction
133 ThermalProperties rbProps = getThermalProperties(BodyLock::NOLOCK);
135
136 const double keLost = 0.5 * pm.getMass(BodyLock::NOLOCK) * static_cast<double>(vRel) * static_cast<double>(vRel);
137 Physics::Thermal::applyThermalEnergy(rbProps, getMass(BodyLock::NOLOCK), keLost * 0.5);
139
140 const double contactArea = kContactAreaFraction * std::min(getSurfaceArea(), pm.getSurfaceArea());
141 const double distance = kContactConductionDistance;
143 rbProps, getMass(BodyLock::NOLOCK),
144 pmProps, pm.getMass(BodyLock::NOLOCK),
145 contactArea, distance, dt
146 );
147
148 setThermalProperty(rbProps, BodyLock::NOLOCK);
150
151 return true;
152}
153
155 return false;
156}
glm::vec3 velocity
Definition PhysicsBody.h:38
BodyLock
Definition PhysicsBody.h:25
glm::vec3 position
Definition PhysicsBody.h:37
virtual double getMass(BodyLock lock) const
void setPosition(const glm::vec3 &pos, BodyLock lock)
float getSurfaceArea() const
Definition PhysicsBody.h:71
glm::vec3 getVelocity(BodyLock lock) const
virtual ThermalProperties getThermalProperties(BodyLock lock) const
std::map< std::string, glm::vec3 > getAllForces(BodyLock lock) const
void setWorldTransform(const glm::mat4 &M, BodyLock lock)
virtual bool collidesWithRigidBody(const RigidBody &rb) const =0
glm::vec3 getPosition(BodyLock lock) const
std::mutex stateMutex
Definition PhysicsBody.h:96
void setForce(const std::string &name, const glm::vec3 &force, BodyLock lock)
virtual void setMass(double newMass, BodyLock lock)
virtual bool resolveCollisionWithRigidBody(float dt, RigidBody &rb)=0
void setIsStatic(bool newStatic, BodyLock lock)
void applyImpulse(const glm::vec3 &impulse, BodyLock lock)
Definition PointMass.cpp:60
void setThermalProperty(const ThermalProperties &newProps, BodyLock lock) override
Definition PointMass.cpp:40
bool resolveCollisionWith(float dt, PhysicsBody &other) override
RigidBody(uint32_t id, double mass, std::unique_ptr< Bounding::ICollider > collider, glm::vec3 pos=glm::vec3(0.0f), bool isStatic=false)
Definition RigidBody.cpp:43
bool collidesWith(const PhysicsBody &other) const override
Definition RigidBody.cpp:94
bool collidesWithPointMass(const PointMass &pm) const override
Definition RigidBody.cpp:98
bool resolveCollisionWithPointMass(float dt, PointMass &pm) override
bool resolveCollisionWithRigidBody(float dt, RigidBody &rb) override
void recordFrame(float t, BodyLock lock) override
Definition RigidBody.cpp:61
bool collidesWithRigidBody(const RigidBody &rb) const override
void step(float dt, BodyLock lock) override
Definition RigidBody.cpp:81
void loadFrame(const ObjectSnapshot &snapshot, BodyLock lock) override
Definition RigidBody.cpp:69
void setGeometry(const std::vector< glm::vec3 > &vertices, const std::vector< unsigned int > &indices)
Definition RigidBody.cpp:22
void setScale(const glm::vec3 &newScale)
Definition RigidBody.cpp:16
float penetration
Penetration depth (positive = overlapping, negative = separated)
Definition ICollider.h:38
glm::vec3 normal
Surface normal at contact point (points outward from surface)
Definition ICollider.h:37
Contact point information from collision queries.
Definition ICollider.h:35
void applyConductiveExchange(ThermalProperties &a, double massA, ThermalProperties &b, double massB, double areaM2, double distanceM, double dt)
void applyThermalEnergy(ThermalProperties &props, double massKg, double energyJ)