Physics Simulation & Visualization Tool 0.1
A C++ physics simulation engine with real-time 3D visualization
Loading...
Searching...
No Matches
Scene.cpp
Go to the documentation of this file.
1#include "Scene.h"
2#include <iostream>
3#include <algorithm>
4#include <cmath>
5#include <limits>
6
7#include "math/MathUtils.h"
9#include <glm/gtc/type_ptr.hpp>
10#include <optional>
12
13#include "ui/OpenGLWindow.h"
14
15namespace {
16constexpr float kFloatingOriginThreshold = 1.0e6f;
17constexpr float kNearClipDepthFraction = 0.05f;
18constexpr float kFarClipPaddingMultiplier = 1.25f;
19constexpr float kMinFarthestDepthOffset = 1.0f;
20constexpr float kMaxNearClipFractionOfFarClip = 0.5f;
21
22float maxAbsComponent(const glm::vec3& v) {
23 return std::max({std::abs(v.x), std::abs(v.y), std::abs(v.z)});
24}
25
26std::optional<std::pair<float, float>> viewDepthSpan(const SceneObject& obj, const glm::vec3& cameraPosition, const glm::vec3& cameraFront) {
27 Mesh* mesh = obj.getMesh();
28 if (!mesh) return std::nullopt;
29
30 const auto& aabb = mesh->getLocalAABB();
31 const glm::vec3 min = aabb.getAABBMin();
32 const glm::vec3 max = aabb.getAABBMax();
33 const glm::mat4 model = obj.getModelMatrix();
34
35 float nearDepth = std::numeric_limits<float>::max();
36 float farDepth = -std::numeric_limits<float>::max();
37
38 for (int x = 0; x < 2; ++x) {
39 for (int y = 0; y < 2; ++y) {
40 for (int z = 0; z < 2; ++z) {
41 const glm::vec3 corner(
42 x ? max.x : min.x,
43 y ? max.y : min.y,
44 z ? max.z : min.z
45 );
46 const glm::vec3 world = glm::vec3(model * glm::vec4(corner, 1.0f));
47 const float depth = glm::dot(world - cameraPosition, cameraFront);
48 nearDepth = std::min(nearDepth, depth);
49 farDepth = std::max(farDepth, depth);
50 }
51 }
52 }
53
54 if (!std::isfinite(nearDepth) || !std::isfinite(farDepth)) {
55 return std::nullopt;
56 }
57
58 return std::pair{nearDepth, farDepth};
59}
60}
61
62struct BatchKey {
65
66 bool operator<(const BatchKey& other) const {
67 if (mesh != other.mesh) return mesh < other.mesh;
68 return shader < other.shader;
69 }
70};
71
72Scene::Scene(QOpenGLFunctions_4_5_Core* glFuncs) : funcs(glFuncs), camera(Camera(glm::vec3(0.0f, 10.0f, 30.0f))), basicShader(nullptr), cameraUBO(2*sizeof(glm::mat4), 0, funcs), hoverUBO(sizeof(glm::ivec4) * 1024, 1, funcs), selectUBO(sizeof(glm::ivec4) * 1024, 2, funcs) {
74 basicShader = ResourceManager::loadShader("assets/shaders/primitive/primitive.vert", "assets/shaders/primitive/primitive.frag", "basic");
75 ResourceManager::loadShader("assets/shaders/primitive/checkerboard.vert", "assets/shaders/primitive/checkerboard.frag", "checkerboard");
76}
77
79 if (!freeIDs.empty()) {
80 uint32_t id = freeIDs.back();
81 freeIDs.pop_back();
82 return id;
83 }
84 return nextID++;
85}
86
87void Scene::freeObjectID(uint32_t objID) {
88 freeIDs.push_back(objID);
89}
90
91void Scene::draw(const std::optional<std::vector<ObjectSnapshot>>& snaps, const std::unordered_set<uint32_t>& hoveredIDs, const std::unordered_set<uint32_t>& selectedIDs) {
92 SceneObject::PosMap renderPositions;
93 if (snaps) {
94 renderPositions.reserve(snaps->size());
95 for (const auto &s : *snaps) {
96 renderPositions.emplace(s.body, s.position);
97 }
98 SceneObject::setPhysicsPosMap(renderPositions);
99 }
100
101 glm::vec3 renderTargetPosition;
102 const glm::vec3* renderTargetPositionPtr = nullptr;
103 if (snaps && camera.hasTarget()) {
104 const SceneObject* target = camera.getTarget();
105 const Physics::PhysicsBody* targetBody = target ? target->getPhysicsBody() : nullptr;
106 for (const auto& snapshot : *snaps) {
107 if (snapshot.body == targetBody) {
108 renderTargetPosition = snapshot.position;
109 renderTargetPositionPtr = &renderTargetPosition;
110 break;
111 }
112 }
113 }
114
115 camera.update(renderTargetPositionPtr);
116
117 float nearestDepth = std::numeric_limits<float>::max();
118 float farthestDepth = Camera::kDefaultNearClip + kMinFarthestDepthOffset;
119 bool foundVisibleDepth = false;
120
121 for (auto* drawable : instancedDrawables) {
122 auto* obj = dynamic_cast<SceneObject*>(drawable);
123 if (!obj) continue;
124
125 const auto depthSpan = viewDepthSpan(*obj, camera.position, camera.front);
126 if (!depthSpan) continue;
127 if (depthSpan->second <= Camera::kDefaultNearClip) continue;
128
129 foundVisibleDepth = true;
130 nearestDepth = std::min(nearestDepth, std::max(depthSpan->first, Camera::kDefaultNearClip));
131 farthestDepth = std::max(farthestDepth, depthSpan->second);
132 }
133
134 if (foundVisibleDepth) {
135 const float farClip = std::max(farthestDepth * kFarClipPaddingMultiplier, Camera::kDefaultFarClip);
136 const float nearClip = nearestDepth == std::numeric_limits<float>::max()
138 : std::clamp(nearestDepth * kNearClipDepthFraction, Camera::kDefaultNearClip, farClip * kMaxNearClipFractionOfFarClip);
139 camera.setClipRange(nearClip, farClip);
140 } else {
142 }
143
144 const bool useFloatingOrigin = maxAbsComponent(camera.position) >= kFloatingOriginThreshold;
145 SceneObject::setRenderOrigin(useFloatingOrigin ? camera.position : glm::vec3(0.0f));
146
147 glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
148 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
149
150 const glm::mat4 viewMatrix = useFloatingOrigin ? camera.getRenderViewMatrix() : camera.getViewMatrix();
151 cameraUBO.updateData(glm::value_ptr(camera.getProjMatrix()), sizeof(glm::mat4), 0);
152 cameraUBO.updateData(glm::value_ptr(viewMatrix), sizeof(glm::mat4), sizeof(glm::mat4));
153
154 std::vector<glm::ivec4> hoverVec(1024, glm::ivec4(0));
155 for (uint32_t id : hoveredIDs) {
156 if (id < hoverVec.size()) {
157 hoverVec[id] = glm::ivec4(1);
158 }
159 }
160
161 std::vector<glm::ivec4> selectVec(1024, glm::ivec4(0));
162 for (uint32_t id : selectedIDs) {
163 if (id < selectVec.size()) {
164 selectVec[id] = glm::ivec4(1);
165 }
166 }
167
168 hoverUBO.updateData(hoverVec.data(), hoverVec.size() * sizeof(glm::ivec4));
169 selectUBO.updateData(selectVec.data(), selectVec.size() * sizeof(glm::ivec4));
170
171 // --- instanced ---
172 std::map<BatchKey, std::vector<Rendering::InstanceData>> batches;
173
174 for (auto* obj : instancedDrawables) {
175 BatchKey key{ obj->getMesh(), obj->getShader() };
176 batches[key].push_back(obj->getInstanceData());
177 }
178
179 for (auto& [key, instances] : batches) {
180 key.shader->use();
181 key.shader->setVec3("renderOrigin", SceneObject::getRenderOrigin());
182 key.mesh->drawInstanced(instances);
183 }
184
185 for (auto* obj : customDrawables) {
186 obj->draw();
187 }
188}
189
191 return &camera;
192}
193
195 assert(drawable != nullptr);
196
197 if (auto instanced = dynamic_cast<IInstancedDrawable*>(drawable)) {
198 instancedDrawables.push_back(instanced);
199 } else if (auto custom = dynamic_cast<ICustomDrawable*>(drawable)) {
200 customDrawables.push_back(custom);
201 }
202}
203
205 assert(drawable != nullptr);
206
207 if (auto instanced = dynamic_cast<IInstancedDrawable*>(drawable)) {
208 instancedDrawables.erase(
209 std::remove(instancedDrawables.begin(), instancedDrawables.end(), instanced),
210 instancedDrawables.end()
211 );
212 } else if (auto custom = dynamic_cast<ICustomDrawable*>(drawable)) {
213 customDrawables.erase(
214 std::remove(customDrawables.begin(), customDrawables.end(), custom),
215 customDrawables.end()
216 );
217 }
218}
Mathematical utility functions for 3D graphics and physics.
glm::vec3 position
Definition Camera.h:15
glm::mat4 getProjMatrix() const
Definition Camera.cpp:46
void update(const glm::vec3 *renderTargetPosition=nullptr)
Definition Camera.cpp:118
glm::mat4 getViewMatrix() const
Definition Camera.cpp:38
void setClipRange(float nearPlane, float farPlane)
Definition Camera.cpp:58
glm::mat4 getRenderViewMatrix() const
Definition Camera.cpp:42
glm::vec3 front
Definition Camera.h:16
const SceneObject * getTarget() const
Definition Camera.h:49
static constexpr float kDefaultNearClip
Definition Camera.h:27
bool hasTarget() const
Definition Camera.h:48
static constexpr float kDefaultFarClip
Definition Camera.h:28
Interface for objects with specialized rendering requirements.
Definition IDrawable.h:181
Base interface for all renderable objects in the scene.
Definition IDrawable.h:33
Interface for objects that support GPU instanced rendering.
Definition IDrawable.h:111
GPU mesh representation with support for instanced rendering.
Definition Mesh.h:58
const Physics::Bounding::AABB & getLocalAABB() const
Gets the local-space axis-aligned bounding box.
Definition Mesh.h:163
glm::vec3 getAABBMin() const override
Gets the minimum, maximum corner of the axis-aligned bounding box (AABB) that contains this collider.
Definition AABB.h:21
static void loadPrimitives()
static Shader * loadShader(const std::string &vShaderPath, const std::string &fShaderPath, const std::string &name)
glm::mat4 getModelMatrix() const override
Gets the model transformation matrix for this instance.
static glm::vec3 getRenderOrigin()
Definition SceneObject.h:64
Rendering::InstanceData getInstanceData() const override
Gets the complete per-instance data for GPU upload.
std::unordered_map< Physics::PhysicsBody *, glm::vec3 > PosMap
Definition SceneObject.h:53
Shader * getShader() const override
Gets the shader used to render this object.
Physics::PhysicsBody * getPhysicsBody() const
Definition SceneObject.h:39
static void setPhysicsPosMap(const PosMap &m)
Definition SceneObject.h:55
static void setRenderOrigin(const glm::vec3 &origin)
Definition SceneObject.h:60
Mesh * getMesh() const override
Gets the mesh geometry for this object.
Definition SceneObject.h:46
void freeObjectID(uint32_t objID)
Definition Scene.cpp:87
void removeDrawable(IDrawable *drawable)
Definition Scene.cpp:204
uint32_t allocateObjectID()
Definition Scene.cpp:78
Camera * getCamera()
Definition Scene.cpp:190
void addDrawable(IDrawable *drawable)
Definition Scene.cpp:194
Scene(QOpenGLFunctions_4_5_Core *glFuncs)
Definition Scene.cpp:72
void draw(const std::optional< std::vector< ObjectSnapshot > > &snapshots, const std::unordered_set< uint32_t > &hoverIDs, const std::unordered_set< uint32_t > &selectIDs)
Definition Scene.cpp:91
Definition Shader.h:6
void use() const
Definition Shader.cpp:55
void updateData(const void *data, unsigned int size, unsigned int offset=0)
bool operator<(const BatchKey &other) const
Definition Scene.cpp:66
Shader * shader
Definition Scene.cpp:64
Mesh * mesh
Definition Scene.cpp:63