载入中...
搜索中...
未找到
World3DJoints.cpp
浏览该文件的文档.
1#include "physics/World3D.h"
2
3#include "physics/Body3D.h"
4#include "physics/Joint3D.h"
6#include "common/Exception.h"
7
8#include <box3d/box3d.h>
9
10#include <cmath>
11
12namespace eve::physics {
13namespace {
14
15void requireFiniteJointParams(const float *values, int count, const char *operation) {
16 for (int i = 0; i < count; ++i) {
17 if (!std::isfinite(values[i]))
18 throw eve::Exception("%s: parameters must be finite", operation);
19 }
20}
21
22void requireDistinctBodies(World3D *world, Body3D *bodyA, Body3D *bodyB, const char *operation) {
23 if (!world || !world->isValid() || !bodyA || !bodyB || !bodyA->isValid() || !bodyB->isValid() ||
24 bodyA->getWorld() != world || bodyB->getWorld() != world || bodyA == bodyB)
25 throw eve::Exception("%s: bodies must be distinct and belong to this world", operation);
26}
27
28b3Vec3 normalizedAxis(float x, float y, float z, const char *operation) {
29 const float length = std::sqrt(x * x + y * y + z * z);
30 if (length <= 1e-8f) throw eve::Exception("%s: axis length must be > 0", operation);
31 return b3Vec3{x / length, y / length, z / length};
32}
33
34} // namespace
35
36Joint3D *World3D::newWeldJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY,
37 float anchorZ, bool collideConnected) {
38 requireDistinctBodies(this, bodyA, bodyB, "World3D.newWeldJoint");
39 const float values[] = {anchorX, anchorY, anchorZ};
40 requireFiniteJointParams(values, 3, "World3D.newWeldJoint");
41 const b3Pos anchor{anchorX, anchorY, anchorZ};
42 const b3WorldTransform xfA = b3Body_GetTransform(bodyA->raw());
43 const b3WorldTransform xfB = b3Body_GetTransform(bodyB->raw());
44 b3WeldJointDef def = b3DefaultWeldJointDef();
45 def.base.bodyIdA = bodyA->raw();
46 def.base.bodyIdB = bodyB->raw();
47 def.base.localFrameA.p = b3Body_GetLocalPoint(bodyA->raw(), anchor);
48 def.base.localFrameB.p = b3Body_GetLocalPoint(bodyB->raw(), anchor);
49 def.base.localFrameA.q = b3InvMulQuat(xfA.q, b3Quat_identity);
50 def.base.localFrameB.q = b3InvMulQuat(xfB.q, b3Quat_identity);
51 def.base.collideConnected = collideConnected;
53 const b3JointId id = b3CreateWeldJoint(worldId_, &def);
54 auto *joint = new Joint3D(this, bodyA, bodyB, id, runtimeHandle, Joint3D::Kind::Weld, nextJointId());
55 b3Joint_SetUserData(id, joint);
56 joints_.insert(joint);
57 jointHandles_[runtimeHandle] = joint;
58 return joint;
59}
60
61Joint3D *World3D::newMotorJoint(Body3D *bodyA, Body3D *bodyB, bool collideConnected) {
62 requireDistinctBodies(this, bodyA, bodyB, "World3D.newMotorJoint");
63 b3MotorJointDef def = b3DefaultMotorJointDef();
64 def.base.bodyIdA = bodyA->raw();
65 def.base.bodyIdB = bodyB->raw();
66 def.base.collideConnected = collideConnected;
68 const b3JointId id = b3CreateMotorJoint(worldId_, &def);
69 auto *joint = new Joint3D(this, bodyA, bodyB, id, runtimeHandle, Joint3D::Kind::Motor, nextJointId());
70 b3Joint_SetUserData(id, joint);
71 joints_.insert(joint);
72 jointHandles_[runtimeHandle] = joint;
73 return joint;
74}
75
77 float axisZ, bool collideConnected) {
78 requireDistinctBodies(this, bodyA, bodyB, "World3D.newParallelJoint");
79 const float values[] = {axisX, axisY, axisZ};
80 requireFiniteJointParams(values, 3, "World3D.newParallelJoint");
81 const b3Vec3 worldAxis = normalizedAxis(axisX, axisY, axisZ, "World3D.newParallelJoint");
82 b3ParallelJointDef def = b3DefaultParallelJointDef();
83 def.base.bodyIdA = bodyA->raw();
84 def.base.bodyIdB = bodyB->raw();
85 def.base.localFrameA.q = b3ComputeQuatBetweenUnitVectors(
86 b3Vec3_axisZ, b3Body_GetLocalVector(bodyA->raw(), worldAxis));
87 def.base.localFrameB.q = b3ComputeQuatBetweenUnitVectors(
88 b3Vec3_axisZ, b3Body_GetLocalVector(bodyB->raw(), worldAxis));
89 def.base.collideConnected = collideConnected;
91 const b3JointId id = b3CreateParallelJoint(worldId_, &def);
92 auto *joint =
93 new Joint3D(this, bodyA, bodyB, id, runtimeHandle, Joint3D::Kind::Parallel, nextJointId());
94 b3Joint_SetUserData(id, joint);
95 joints_.insert(joint);
96 jointHandles_[runtimeHandle] = joint;
97 return joint;
98}
99
101 requireDistinctBodies(this, bodyA, bodyB, "World3D.newFilterJoint");
102 b3FilterJointDef def = b3DefaultFilterJointDef();
103 def.base.bodyIdA = bodyA->raw();
104 def.base.bodyIdB = bodyB->raw();
106 const b3JointId id = b3CreateFilterJoint(worldId_, &def);
107 auto *joint =
108 new Joint3D(this, bodyA, bodyB, id, runtimeHandle, Joint3D::Kind::Filter, nextJointId());
109 b3Joint_SetUserData(id, joint);
110 joints_.insert(joint);
111 jointHandles_[runtimeHandle] = joint;
112 return joint;
113}
114
116 if (!mechanism) return;
117 mechanisms_.erase(mechanism);
118}
119
120int World3D::nextMechanismId() { return nextMechanismId_++; }
121
122Mechanism3D *World3D::newShaft(Body3D *support, Body3D *rotor, float anchorX, float anchorY,
123 float anchorZ, float axisX, float axisY, float axisZ,
124 bool collideConnected) {
125 requireDistinctBodies(this, support, rotor, "World3D.newShaft");
126 const b3Vec3 axis = normalizedAxis(axisX, axisY, axisZ, "World3D.newShaft");
127 Joint3D *drive =
128 newRevoluteJoint(support, rotor, anchorX, anchorY, anchorZ, axis.x, axis.y, axis.z,
129 collideConnected);
130 auto *mechanism = new Mechanism3D(this, Mechanism3D::Kind::Shaft, nextMechanismId(), drive,
131 nullptr, nullptr, nullptr, axis.x, axis.y, axis.z, 1, 0.f);
132 mechanisms_.insert(mechanism);
133 return mechanism;
134}
135
136Mechanism3D *World3D::newRatchet(Body3D *frame, Body3D *wheel, float anchorX, float anchorY,
137 float anchorZ, float axisX, float axisY, float axisZ,
138 int direction, float engagementTorque, bool collideConnected) {
139 requireDistinctBodies(this, frame, wheel, "World3D.newRatchet");
140 if (direction != 1 && direction != -1)
141 throw eve::Exception("World3D.newRatchet: direction must be +1 or -1");
142 if (!std::isfinite(engagementTorque) || engagementTorque < 0.f)
143 throw eve::Exception("World3D.newRatchet: engagementTorque must be finite and >= 0");
144 const b3Vec3 axis = normalizedAxis(axisX, axisY, axisZ, "World3D.newRatchet");
145 Joint3D *drive =
146 newRevoluteJoint(frame, wheel, anchorX, anchorY, anchorZ, axis.x, axis.y, axis.z,
147 collideConnected);
148 auto *mechanism =
149 new Mechanism3D(this, Mechanism3D::Kind::Ratchet, nextMechanismId(), drive, nullptr,
150 nullptr, nullptr, axis.x, axis.y, axis.z, direction, engagementTorque);
151 mechanisms_.insert(mechanism);
152 return mechanism;
153}
154
156 float crankAnchorX, float crankAnchorY, float crankAnchorZ,
157 float axisX, float axisY, float axisZ, float crankPinX,
158 float crankPinY, float crankPinZ, float sliderPinX,
159 float sliderPinY, float sliderPinZ, float slideAxisX,
160 float slideAxisY, float slideAxisZ, bool collideConnected) {
161 requireDistinctBodies(this, frame, crank, "World3D.newCrankSlider");
162 requireDistinctBodies(this, crank, rod, "World3D.newCrankSlider");
163 requireDistinctBodies(this, rod, slider, "World3D.newCrankSlider");
164 requireDistinctBodies(this, frame, slider, "World3D.newCrankSlider");
165 if (frame == rod || crank == slider)
166 throw eve::Exception("World3D.newCrankSlider: bodies must form a four-bar chain");
167 const float values[] = {crankAnchorX, crankAnchorY, crankAnchorZ, axisX, axisY,
168 axisZ, crankPinX, crankPinY, crankPinZ, sliderPinX,
169 sliderPinY, sliderPinZ, slideAxisX, slideAxisY, slideAxisZ};
170 requireFiniteJointParams(values, 15, "World3D.newCrankSlider");
171 const b3Vec3 hingeAxis = normalizedAxis(axisX, axisY, axisZ, "World3D.newCrankSlider");
172 const b3Vec3 slideAxis =
173 normalizedAxis(slideAxisX, slideAxisY, slideAxisZ, "World3D.newCrankSlider");
174 if (std::fabs(b3Dot(hingeAxis, slideAxis)) > 0.999f)
175 throw eve::Exception("World3D.newCrankSlider: hinge and slide axes must not be parallel");
176
177 Joint3D *drive =
178 newRevoluteJoint(frame, crank, crankAnchorX, crankAnchorY, crankAnchorZ, hingeAxis.x,
179 hingeAxis.y, hingeAxis.z, collideConnected);
180 Joint3D *crankPin =
181 newRevoluteJoint(crank, rod, crankPinX, crankPinY, crankPinZ, hingeAxis.x, hingeAxis.y,
182 hingeAxis.z, collideConnected);
183 Joint3D *sliderPin =
184 newRevoluteJoint(rod, slider, sliderPinX, sliderPinY, sliderPinZ, hingeAxis.x, hingeAxis.y,
185 hingeAxis.z, collideConnected);
186 Joint3D *prismatic =
187 newPrismaticJoint(frame, slider, sliderPinX, sliderPinY, sliderPinZ, slideAxis.x,
188 slideAxis.y, slideAxis.z, collideConnected);
189 auto *mechanism =
190 new Mechanism3D(this, Mechanism3D::Kind::CrankSlider, nextMechanismId(), drive, crankPin,
191 sliderPin, prismatic, hingeAxis.x, hingeAxis.y, hingeAxis.z, 1, 0.f);
192 mechanisms_.insert(mechanism);
193 return mechanism;
194}
195
196} // namespace eve::physics
ActionParameterOperation operation
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
float length
Definition CaveMesh.cpp:94
Vec3 anchor
Definition CaveMesh.cpp:90
std::map< std::string, Var > values
World3D * world
RoadLaneDirection direction
float axisZ
Definition RockMesh.cpp:22
float axisY
Definition RockMesh.cpp:22
float axisX
Definition RockMesh.cpp:22
std::uint32_t count
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create pr...
Definition Body3D.h:24
b3BodyId raw() const
Raw.
Definition Body3D.h:349
Script-facing Box3D joint owned by a World3D.
Definition Joint3D.h:17
Composed mechanical assembly owned by a World3D.
Definition Mechanism3D.h:25
PhysicsJointHandle nextJointRuntimeHandle()
Internal: next generation-qualified joint handle.
Definition World3D.cpp:896
Joint3D * newMotorJoint(Body3D *bodyA, Body3D *bodyB, bool collideConnected=false)
Creates a motor joint that drives relative linear/angular velocity between bodies.
PhysicsWorldHandle runtimeHandle() const noexcept
Process-local identity used by PhysicsLink; invalid after destruction.
Definition World3D.h:141
Joint3D * newWeldJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, bool collideConnected=false)
Welds two bodies at a shared world-space anchor, preserving current relative pose.
Joint3D * newParallelJoint(Body3D *bodyA, Body3D *bodyB, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a parallel joint that spring-aligns body local Z axes to a world axis.
Joint3D * newRevoluteJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a hinge around a normalized world-space axis at a shared anchor.
Definition World3D.cpp:562
int nextJointId()
Internal: next stable joint id.
Definition World3D.h:994
Mechanism3D * newCrankSlider(Body3D *frame, Body3D *crank, Body3D *rod, Body3D *slider, float crankAnchorX, float crankAnchorY, float crankAnchorZ, float axisX, float axisY, float axisZ, float crankPinX, float crankPinY, float crankPinZ, float sliderPinX, float sliderPinY, float sliderPinZ, float slideAxisX, float slideAxisY, float slideAxisZ, bool collideConnected=false)
Builds a planar crank-slider from frame, crank, connecting rod and slider bodies.
bool isValid() const
True while the underlying Box3D world is alive.
Definition World3D.cpp:430
Mechanism3D * newRatchet(Body3D *frame, Body3D *wheel, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, int direction, float engagementTorque, bool collideConnected=false)
Builds a one-way ratchet around a revolute axis.
Joint3D * newFilterJoint(Body3D *bodyA, Body3D *bodyB)
Disables collision between two specific bodies (filter joint).
Joint3D * newPrismaticJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a slider whose permitted world-space translation follows axis.
Definition World3D.cpp:597
Mechanism3D * newShaft(Body3D *support, Body3D *rotor, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Builds a shaft (support↔rotor revolute) with optional drive motor helpers.
void forgetMechanism(Mechanism3D *mechanism)
Internal: removes a mechanism wrapper from ownership bookkeeping.
friend class Joint3D
Definition World3D.h:1005
friend class Mechanism3D
Definition World3D.h:1006
int nextMechanismId()
Internal: next stable mechanism id.
Optional physics backend for vehicle mobility and body attach.
Definition Climbing.h:36