Skip to content

Commit 92140a3

Browse files
ThomasParenteauiMeaNz
authored andcommitted
feat: physics inscpector
1 parent 4869c8e commit 92140a3

1 file changed

Lines changed: 223 additions & 3 deletions

File tree

editor/src/DocumentWindows/EntityProperties/PhysicsBodyProperty.cpp

Lines changed: 223 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#include "components/Transform.hpp"
2222
#include "systems/PhysicsSystem.hpp"
2323

24+
#include <Jolt/Physics/Body/BodyLockInterface.h>
25+
#include <Jolt/Physics/Body/MotionProperties.h>
26+
2427
namespace nexo::editor {
2528

2629
void PhysicsBodyProperty::show(const ecs::Entity entity)
@@ -51,12 +54,228 @@ namespace nexo::editor {
5154
}
5255

5356
ImGui::Separator();
54-
ImGui::Text("Body ID: %u", physicsBody.bodyID.GetIndex());
5557

5658
const auto& app = Application::getInstance();
5759
if (const auto physicsSystem = app.getPhysicsSystem()) {
58-
const bool isActive = physicsSystem->getBodyInterface()->IsActive(physicsBody.bodyID);
59-
ImGui::Text("Active: %s", isActive ? "Yes" : "No");
60+
auto* bodyInterface = physicsSystem->getBodyInterface();
61+
const JPH::BodyID bodyID = physicsBody.bodyID;
62+
63+
// Debug Info Section
64+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
65+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
66+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
67+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
68+
const bool debugOpen = ImGui::CollapsingHeader("Debug Information", ImGuiTreeNodeFlags_DefaultOpen);
69+
ImGui::PopStyleColor(4);
70+
71+
if (debugOpen) {
72+
ImGui::Text("Body ID: %u", bodyID.GetIndex());
73+
const bool isActive = bodyInterface->IsActive(bodyID);
74+
ImGui::Text("Active: %s", isActive ? "Yes" : "No");
75+
76+
// Position (read-only, comes from transform)
77+
const JPH::Vec3 pos = bodyInterface->GetPosition(bodyID);
78+
ImGui::Text("Position: (%.2f, %.2f, %.2f)", pos.GetX(), pos.GetY(), pos.GetZ());
79+
}
80+
81+
// Only show physics properties for dynamic bodies
82+
if (currentType == components::PhysicsBodyComponent::Type::Dynamic) {
83+
84+
// Mass Properties
85+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
86+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
87+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
88+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
89+
const bool massOpen = ImGui::CollapsingHeader("Mass Properties", ImGuiTreeNodeFlags_DefaultOpen);
90+
ImGui::PopStyleColor(4);
91+
92+
if (massOpen) {
93+
// Get mass info (read-only for now as Jolt mass editing requires shape recreation)
94+
const auto lockInterface = physicsSystem->getBodyLockInterface();
95+
JPH::BodyLockRead lock(*lockInterface, bodyID);
96+
if (lock.Succeeded()) {
97+
const JPH::Body& body = lock.GetBody();
98+
const JPH::MotionProperties* motionProps = body.GetMotionProperties();
99+
100+
if (motionProps) {
101+
const float invMass = motionProps->GetInverseMass();
102+
const float mass = invMass > 0.0f ? 1.0f / invMass : 0.0f;
103+
104+
ImGui::Text("Mass: %.3f kg", mass);
105+
ImGui::Text("Inverse Mass: %.6f", invMass);
106+
107+
if (ImGui::IsItemHovered()) {
108+
ImGui::SetTooltip("Mass is determined by shape and density.\nRecreate body to change mass.");
109+
}
110+
}
111+
}
112+
}
113+
114+
// Velocity Controls
115+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
116+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
117+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
118+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
119+
const bool velocityOpen = ImGui::CollapsingHeader("Velocity", ImGuiTreeNodeFlags_DefaultOpen);
120+
ImGui::PopStyleColor(4);
121+
122+
if (velocityOpen) {
123+
// Linear Velocity
124+
JPH::Vec3 linVel = bodyInterface->GetLinearVelocity(bodyID);
125+
float linVelArray[3] = {linVel.GetX(), linVel.GetY(), linVel.GetZ()};
126+
127+
if (ImGui::DragFloat3("Linear Velocity", linVelArray, 0.1f, -100.0f, 100.0f, "%.2f m/s")) {
128+
bodyInterface->SetLinearVelocity(bodyID, JPH::Vec3(linVelArray[0], linVelArray[1], linVelArray[2]));
129+
}
130+
131+
// Angular Velocity
132+
JPH::Vec3 angVel = bodyInterface->GetAngularVelocity(bodyID);
133+
float angVelArray[3] = {angVel.GetX(), angVel.GetY(), angVel.GetZ()};
134+
135+
if (ImGui::DragFloat3("Angular Velocity", angVelArray, 0.1f, -10.0f, 10.0f, "%.2f rad/s")) {
136+
bodyInterface->SetAngularVelocity(bodyID, JPH::Vec3(angVelArray[0], angVelArray[1], angVelArray[2]));
137+
}
138+
139+
// Quick reset button
140+
if (ImGui::Button("Reset Velocities")) {
141+
bodyInterface->SetLinearVelocity(bodyID, JPH::Vec3::sZero());
142+
bodyInterface->SetAngularVelocity(bodyID, JPH::Vec3::sZero());
143+
}
144+
}
145+
146+
// Physics Material Properties
147+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
148+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
149+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
150+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
151+
const bool materialOpen = ImGui::CollapsingHeader("Material Properties", ImGuiTreeNodeFlags_DefaultOpen);
152+
ImGui::PopStyleColor(4);
153+
154+
if (materialOpen) {
155+
const auto lockInterface = physicsSystem->getBodyLockInterface();
156+
JPH::BodyLockRead lock(*lockInterface, bodyID);
157+
if (lock.Succeeded()) {
158+
const JPH::Body& body = lock.GetBody();
159+
160+
// Friction
161+
float friction = body.GetFriction();
162+
if (ImGui::SliderFloat("Friction", &friction, 0.0f, 1.0f, "%.3f")) {
163+
bodyInterface->SetFriction(bodyID, friction);
164+
}
165+
if (ImGui::IsItemHovered()) {
166+
ImGui::SetTooltip("Surface friction (0 = ice, 1 = rubber)");
167+
}
168+
169+
// Restitution (Bounciness)
170+
float restitution = body.GetRestitution();
171+
if (ImGui::SliderFloat("Restitution", &restitution, 0.0f, 1.0f, "%.3f")) {
172+
bodyInterface->SetRestitution(bodyID, restitution);
173+
}
174+
if (ImGui::IsItemHovered()) {
175+
ImGui::SetTooltip("Bounciness (0 = no bounce, 1 = perfect bounce)");
176+
}
177+
}
178+
}
179+
180+
// Constraints and Limits
181+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
182+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
183+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
184+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
185+
const bool constraintsOpen = ImGui::CollapsingHeader("Constraints and Limits");
186+
ImGui::PopStyleColor(4);
187+
188+
if (constraintsOpen) {
189+
const auto lockInterface = physicsSystem->getBodyLockInterface();
190+
191+
// Read current values
192+
float linearDamping = 0.0f;
193+
float angularDamping = 0.0f;
194+
float maxLinVel = 0.0f;
195+
float maxAngVel = 0.0f;
196+
197+
{
198+
JPH::BodyLockRead readLock(*lockInterface, bodyID);
199+
if (readLock.Succeeded()) {
200+
const JPH::Body& body = readLock.GetBody();
201+
const JPH::MotionProperties* motionProps = body.GetMotionProperties();
202+
203+
if (motionProps) {
204+
linearDamping = motionProps->GetLinearDamping();
205+
angularDamping = motionProps->GetAngularDamping();
206+
maxLinVel = motionProps->GetMaxLinearVelocity();
207+
maxAngVel = motionProps->GetMaxAngularVelocity();
208+
}
209+
}
210+
}
211+
212+
// Display and edit
213+
bool needsUpdate = false;
214+
float newLinearDamping = linearDamping;
215+
float newAngularDamping = angularDamping;
216+
217+
if (ImGui::SliderFloat("Linear Damping", &newLinearDamping, 0.0f, 1.0f, "%.3f")) {
218+
needsUpdate = true;
219+
}
220+
if (ImGui::IsItemHovered()) {
221+
ImGui::SetTooltip("Resistance to linear motion (air resistance)");
222+
}
223+
224+
if (ImGui::SliderFloat("Angular Damping", &newAngularDamping, 0.0f, 1.0f, "%.3f")) {
225+
needsUpdate = true;
226+
}
227+
if (ImGui::IsItemHovered()) {
228+
ImGui::SetTooltip("Resistance to rotation");
229+
}
230+
231+
// Apply changes if needed
232+
if (needsUpdate) {
233+
JPH::BodyLockWrite writeLock(*lockInterface, bodyID);
234+
if (writeLock.Succeeded()) {
235+
JPH::Body& body = writeLock.GetBody();
236+
JPH::MotionProperties* motionProps = body.GetMotionProperties();
237+
238+
if (motionProps) {
239+
motionProps->SetLinearDamping(newLinearDamping);
240+
motionProps->SetAngularDamping(newAngularDamping);
241+
}
242+
}
243+
}
244+
245+
ImGui::Text("Max Linear Velocity: %.1f m/s", maxLinVel);
246+
if (ImGui::IsItemHovered()) {
247+
ImGui::SetTooltip("Maximum linear velocity (set by physics system)");
248+
}
249+
250+
ImGui::Text("Max Angular Velocity: %.1f rad/s", maxAngVel);
251+
if (ImGui::IsItemHovered()) {
252+
ImGui::SetTooltip("Maximum angular velocity (set by physics system)");
253+
}
254+
}
255+
256+
// Real-time Visual Feedback
257+
ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
258+
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
259+
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.15f, 0.15f, 0.15f, 1.0f));
260+
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
261+
const bool debugVizOpen = ImGui::CollapsingHeader("Real-time Debug Visualization");
262+
ImGui::PopStyleColor(4);
263+
264+
if (debugVizOpen) {
265+
static bool showVelocity = false;
266+
static bool showForces = false;
267+
268+
ImGui::Checkbox("Show Velocity Arrows", &showVelocity);
269+
ImGui::Checkbox("Show Applied Forces", &showForces);
270+
271+
if (showVelocity) {
272+
const JPH::Vec3 linVel = bodyInterface->GetLinearVelocity(bodyID);
273+
const float speed = linVel.Length();
274+
ImGui::Text("Current Speed: %.2f m/s", speed);
275+
ImGui::ProgressBar(speed / 50.0f, ImVec2(-1, 0));
276+
}
277+
}
278+
}
60279
}
61280

62281
ImGui::TreePop();
@@ -161,3 +380,4 @@ namespace nexo::editor {
161380
}
162381

163382
} // namespace nexo::editor
383+

0 commit comments

Comments
 (0)