载入中...
搜索中...
未找到
Shape3D.cpp
浏览该文件的文档.
1#include "physics/Shape3D.h"
2#include "physics/Body3D.h"
3#include "physics/World3D.h"
4
5#include "common/Exception.h"
6
7#include <box3d/box3d.h>
8
9namespace eve::physics {
10namespace {
11
12b3ShapeDef makeShapeDef(float density, float friction, float restitution, bool sensor) {
13 b3ShapeDef def = b3DefaultShapeDef();
14 def.density = density;
15 def.baseMaterial.friction = friction;
16 def.baseMaterial.restitution = restitution;
17 def.isSensor = sensor;
18 def.enableContactEvents = !sensor;
19 def.enableSensorEvents = true;
20 return def;
21}
22
23} // namespace
24
25Shape3D::Shape3D(World3D *world, Body3D *body, b3ShapeId shapeId, Kind kind, float a, float b,
26 float c)
27 : world_(world), body_(body), shapeId_(shapeId), kind_(kind), a_(a), b_(b), c_(c) {}
28
30 if (isValid() && body_ && body_->isValid()) {
31 b3Shape_SetUserData(shapeId_, nullptr);
32 b3DestroyShape(shapeId_, true);
33 if (world_) world_->forgetShape(this);
34 }
35 shapeId_ = {};
36 body_ = nullptr;
37 world_ = nullptr;
38}
39
40bool Shape3D::isValid() const { return b3Shape_IsValid(shapeId_); }
41
43 if (isValid()) b3Shape_SetUserData(shapeId_, nullptr);
44 shapeId_ = {};
45 body_ = nullptr;
46 world_ = nullptr;
47}
48
50 if (!isValid() || !body_ || !body_->isValid()) {
51 invalidate();
52 return;
53 }
54 b3Shape_SetUserData(shapeId_, nullptr);
55 b3DestroyShape(shapeId_, true);
56 if (world_) world_->forgetShape(this);
57 shapeId_ = {};
58 body_ = nullptr;
59 world_ = nullptr;
60}
61
62void Shape3D::recreate(bool sensor) {
63 if (!body_ || !body_->isValid())
64 throw eve::Exception("Shape3D.setSensor: body destroyed");
65
66 float density = isValid() ? b3Shape_GetDensity(shapeId_) : 1.f;
67 float friction = isValid() ? b3Shape_GetFriction(shapeId_) : 0.2f;
68 float restitution = isValid() ? b3Shape_GetRestitution(shapeId_) : 0.f;
69
70 if (isValid()) {
71 b3Shape_SetUserData(shapeId_, nullptr);
72 b3DestroyShape(shapeId_, false);
73 shapeId_ = {};
74 }
75
76 b3ShapeDef def = makeShapeDef(density, friction, restitution, sensor);
77 switch (kind_) {
78 case Kind::Box: {
79 b3BoxHull box = b3MakeBoxHull(a_, b_, c_);
80 shapeId_ = b3CreateHullShape(body_->raw(), &def, &box.base);
81 break;
82 }
83 case Kind::Sphere: {
84 b3Sphere sphere;
85 sphere.center = b3Vec3_zero;
86 sphere.radius = a_;
87 shapeId_ = b3CreateSphereShape(body_->raw(), &def, &sphere);
88 break;
89 }
90 case Kind::Capsule: {
91 b3Capsule capsule;
92 capsule.center1 = b3Vec3{0.f, -a_, 0.f};
93 capsule.center2 = b3Vec3{0.f, a_, 0.f};
94 capsule.radius = b_;
95 shapeId_ = b3CreateCapsuleShape(body_->raw(), &def, &capsule);
96 break;
97 }
98 }
99 b3Shape_SetUserData(shapeId_, this);
100}
101
102void Shape3D::setSensor(bool sensor) {
103 if (!body_ || !body_->isValid()) return;
104 if (isValid() && b3Shape_IsSensor(shapeId_) == sensor) return;
105 recreate(sensor);
106}
107
108bool Shape3D::isSensor() const { return isValid() ? b3Shape_IsSensor(shapeId_) : false; }
109
110void Shape3D::setFriction(float friction) {
111 if (!isValid()) return;
112 b3Shape_SetFriction(shapeId_, friction);
113}
114
115float Shape3D::getFriction() const { return isValid() ? b3Shape_GetFriction(shapeId_) : 0.f; }
116
117void Shape3D::setRestitution(float restitution) {
118 if (!isValid()) return;
119 b3Shape_SetRestitution(shapeId_, restitution);
120}
121
123 return isValid() ? b3Shape_GetRestitution(shapeId_) : 0.f;
124}
125
126void Shape3D::setDensity(float density) {
127 if (!isValid()) return;
128 b3Shape_SetDensity(shapeId_, density, true);
129}
130
131float Shape3D::getDensity() const { return isValid() ? b3Shape_GetDensity(shapeId_) : 0.f; }
132
133bool Shape3D::testPoint(float x, float y, float z) const {
134 if (!isValid() || !body_ || !body_->isValid()) return false;
135
136 b3Vec3 point{x, y, z};
137 b3ShapeProxy proxy;
138 proxy.points = &point;
139 proxy.count = 1;
140 proxy.radius = 0.f;
141
142 b3WorldTransform wt = b3Body_GetTransform(body_->raw());
143 b3Transform xf;
144 xf.p = b3Vec3{static_cast<float>(wt.p.x), static_cast<float>(wt.p.y),
145 static_cast<float>(wt.p.z)};
146 xf.q = wt.q;
147
148 switch (kind_) {
149 case Kind::Box: {
150 const b3HullData *hull = b3Shape_GetHull(shapeId_);
151 if (!hull) return false;
152 return b3OverlapHull(hull, xf, &proxy);
153 }
154 case Kind::Sphere: {
155 b3Sphere sphere = b3Shape_GetSphere(shapeId_);
156 return b3OverlapSphere(&sphere, xf, &proxy);
157 }
158 case Kind::Capsule: {
159 b3Capsule capsule = b3Shape_GetCapsule(shapeId_);
160 return b3OverlapCapsule(&capsule, xf, &proxy);
161 }
162 }
163 return false;
164}
165
166} // namespace eve::physics
Tok kind
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
JobFunc body
uint32_t a
uint32_t b
uint32_t c
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create sh...
Definition Body3D.h:16
b3BodyId raw() const
Definition Body3D.h:99
bool isValid() const
True while the underlying Box3D body is still alive.
Definition Body3D.cpp:64
void setDensity(float density)
Definition Shape3D.cpp:126
void invalidate()
Internal: marks the wrapper invalid after destruction.
Definition Shape3D.cpp:42
bool testPoint(float x, float y, float z) const
Point-in-shape test in world meters.
Definition Shape3D.cpp:133
Shape3D(World3D *world, Body3D *body, b3ShapeId shapeId, Kind kind, float a, float b, float c)
Internal: wraps a Box3D shape (use Body3D::new*Shape).
Definition Shape3D.cpp:25
Kind
Shape geometry kind.
Definition Shape3D.h:17
bool isSensor() const
Definition Shape3D.cpp:108
void setRestitution(float restitution)
Definition Shape3D.cpp:117
bool isValid() const
Definition Shape3D.cpp:40
float getFriction() const
Definition Shape3D.cpp:115
float getRestitution() const
Definition Shape3D.cpp:122
void destroy()
Destroys the shape inside its world.
Definition Shape3D.cpp:49
float getDensity() const
Definition Shape3D.cpp:131
void setSensor(bool sensor)
Sensor shapes report contacts but never collide.
Definition Shape3D.cpp:102
void setFriction(float friction)
Material properties.
Definition Shape3D.cpp:110
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
Definition World3D.h:18
void forgetShape(Shape3D *shape)
Definition World3D.cpp:119