Physics Simulation & Visualization Tool 0.1
A C++ physics simulation engine with real-time 3D visualization
Loading...
Searching...
No Matches
Forces.cpp
Go to the documentation of this file.
1#include "Forces.h"
5#include <algorithm>
6#include <glm/gtc/matrix_transform.hpp>
7#include <glm/gtx/component_wise.hpp>
8
9namespace {
10
11constexpr float kArrowStemMin = 1.0f;
12constexpr float kArrowStemMax = 3.5f;
13constexpr float kArrowRadiusMin = 1.0f;
14constexpr float kArrowThicknessScale = 0.08f;
15constexpr float kDefaultArrowStrengthT = 0.5f;
16constexpr float kForceEpsilon = 1e-4f;
17constexpr float kMagSpanEpsilon = 1e-6f;
18constexpr float kParallelAxisEpsilon = 1e-3f;
19constexpr glm::vec3 kArrowColor = glm::vec3(1.0f, 1.0f, 0.0f);
20
21glm::mat4 rotateFromYToDir(const glm::vec3& dir) {
22 const glm::vec3 from(0.0f, 1.0f, 0.0f);
23 const glm::vec3 to = glm::normalize(dir);
24 const glm::vec3 crossA = glm::cross(from, to);
25 const float cosA = glm::dot(from, to);
26
27 if (glm::length(crossA) < kParallelAxisEpsilon) {
28 if (cosA < 0.0f) {
29 return glm::rotate(glm::mat4(1.0f), glm::pi<float>(), glm::vec3(1.0f, 0.0f, 0.0f));
30 }
31 return glm::mat4(1.0f);
32 }
33
34 const float angle = std::acos(glm::clamp(cosA, -1.0f, 1.0f));
35 return glm::rotate(glm::mat4(1.0f), angle, glm::normalize(crossA));
36}
37
38} // namespace
39
40Forces::Forces(SceneManager* sceneManager) : sceneManager(sceneManager) {
41 basicShader = ResourceManager::getShader("basic");
42 if (!basicShader) {
43 basicShader = ResourceManager::loadShader("assets/shaders/primitive/primitive.vert", "assets/shaders/primitive/primitive.frag", "basic");
44 }
45}
46
47void Forces::draw() const {
48 if (!enabled) return;
49
50 auto* arrowMesh = ResourceManager::getMesh("gizmo_translate");
51 if (!arrowMesh || !basicShader) return;
52
53 const auto& objects = sceneManager->getObjects();
54
55 m_arrowScratch.clear();
56 const std::size_t n = objects.size();
57 if (m_arrowScratch.capacity() < n) {
58 m_arrowScratch.reserve(n);
59 }
60
61 float minMag = 0.0f;
62 float maxMag = 0.0f;
63 bool haveSpan = false;
64
65 for (const auto& objPtr : objects) {
66 SceneObject* obj = objPtr.get();
67 auto* body = obj->getPhysicsBody();
68 if (!body) continue;
69
70 const glm::vec3 net = body->getNetForce(BodyLock::LOCK);
71 const float netMag = glm::length(net);
72 if (netMag < kForceEpsilon) continue;
73
74 if (!haveSpan) {
75 minMag = maxMag = netMag;
76 haveSpan = true;
77 } else {
78 minMag = std::min(minMag, netMag);
79 maxMag = std::max(maxMag, netMag);
80 }
81
82 const float radius = glm::compMax(glm::abs(obj->getScale())) * 0.5f;
83 const glm::vec3 dir = glm::normalize(net);
84 const glm::vec3 surfaceStart = body->getPosition(BodyLock::LOCK) + dir * radius;
85 m_arrowScratch.push_back({obj->getObjectID(), net, netMag, surfaceStart, std::max(radius, kArrowRadiusMin)});
86 }
87
88 if (m_arrowScratch.empty()) return;
89
90 basicShader->use();
91
92 const float magSpan = maxMag - minMag;
93 const glm::vec3 renderOrigin = SceneObject::getRenderOrigin();
94
95 m_instanceScratch.clear();
96 if (m_instanceScratch.capacity() < m_arrowScratch.size()) {
97 m_instanceScratch.reserve(m_arrowScratch.size());
98 }
99
100 for (const ArrowCpu& e : m_arrowScratch) {
101 glm::mat4 model(1.0f);
102 model = glm::translate(model, e.startPos - renderOrigin);
103 model = model * rotateFromYToDir(e.net);
104
105 float t = kDefaultArrowStrengthT;
106 if (magSpan > kMagSpanEpsilon) {
107 t = (e.netMag - minMag) / magSpan;
108 }
109 const float lengthFactor = kArrowStemMin + t * (kArrowStemMax - kArrowStemMin);
110
111 model = glm::scale(model, glm::vec3(e.radius * kArrowThicknessScale, e.radius * lengthFactor, e.radius * kArrowThicknessScale));
112 m_instanceScratch.emplace_back(model, e.objectID, kArrowColor);
113 }
114
115 arrowMesh->drawInstanced(m_instanceScratch);
116}
Forces(SceneManager *sceneManager)
Definition Forces.cpp:40
void draw() const override
Performs custom rendering for this object.
Definition Forces.cpp:47
glm::vec3 getNetForce(BodyLock lock) const
static Shader * getShader(const std::string &name)
static Mesh * getMesh(const std::string &name)
static Shader * loadShader(const std::string &vShaderPath, const std::string &fShaderPath, const std::string &name)
const std::vector< std::unique_ptr< SceneObject > > & getObjects() const
glm::vec3 getScale() const
static glm::vec3 getRenderOrigin()
Definition SceneObject.h:64
Physics::PhysicsBody * getPhysicsBody() const
Definition SceneObject.h:39
uint32_t getObjectID() const override
Gets the unique identifier for this object.
void use() const
Definition Shader.cpp:55