collide: First pass at reducing memory overhead of CollisionBox

This is just the low-hanging fruit, there are a lot more gains to be realized.
This commit is contained in:
rdb 2022-03-02 14:38:02 +01:00
parent 21cfb8dba5
commit 8cdac14db3
3 changed files with 63 additions and 125 deletions

View File

@ -17,11 +17,10 @@
*/ */
INLINE CollisionBox:: INLINE CollisionBox::
CollisionBox(const LPoint3 &center, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) : CollisionBox(const LPoint3 &center, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z) :
_center(center), _x(x), _y(y), _z(z) _center(center)
{ {
_min = LPoint3(_center.get_x() - _x, _center.get_y() - _y, _center.get_z() - _z); _min = LPoint3(_center.get_x() - x, _center.get_y() - y, _center.get_z() - z);
_max = LPoint3(_center.get_x() + _x, _center.get_y() + _y, _center.get_z() + _z); _max = LPoint3(_center.get_x() + x, _center.get_y() + y, _center.get_z() + z);
_radius = sqrt(_x*_x + _y*_y + _z*_z);
for(int v = 0; v < 8; v++) for(int v = 0; v < 8; v++)
_vertex[v] = get_point_aabb(v); _vertex[v] = get_point_aabb(v);
for(int p = 0; p < 6; p++) for(int p = 0; p < 6; p++)
@ -37,10 +36,6 @@ CollisionBox(const LPoint3 &min, const LPoint3 &max) :
_min(min), _max(max) _min(min), _max(max)
{ {
_center = (_min + _max) / 2; _center = (_min + _max) / 2;
_x = _center.get_x() - _min.get_x();
_y = _center.get_y() - _min.get_y();
_z = _center.get_z() - _min.get_z();
_radius = sqrt(_x*_x + _y*_y + _z*_z);
for(int v = 0; v < 8; v++) for(int v = 0; v < 8; v++)
_vertex[v] = get_point_aabb(v); _vertex[v] = get_point_aabb(v);
for(int p = 0; p < 6; p++) for(int p = 0; p < 6; p++)
@ -63,11 +58,7 @@ CollisionBox(const CollisionBox &copy) :
CollisionSolid(copy), CollisionSolid(copy),
_center(copy._center), _center(copy._center),
_min(copy._min), _min(copy._min),
_max(copy._max), _max(copy._max)
_x(copy._x ),
_y(copy._y ),
_z(copy._z ),
_radius(copy._radius )
{ {
for(int v = 0; v < 8; v++) for(int v = 0; v < 8; v++)
_vertex[v] = copy._vertex[v]; _vertex[v] = copy._vertex[v];
@ -152,7 +143,6 @@ get_point(int n) const {
return _vertex[n]; return _vertex[n];
} }
/** /**
* Returns the nth vertex of the Axis Aligned Bounding Box. * Returns the nth vertex of the Axis Aligned Bounding Box.
*/ */
@ -243,20 +233,6 @@ calc_to_3d_mat(LMatrix4 &to_3d_mat,int plane) const {
to_3d_mat.set_row(3, get_plane(plane).get_point()); to_3d_mat.set_row(3, get_plane(plane).get_point());
} }
/**
* Fills the indicated matrix with the appropriate rotation transform to move
* points from the 2-d plane into the 3-d (X, 0, Z) plane.
*
* This is essentially similar to calc_to_3d_mat, except that the matrix is
* rederived from whatever is stored in _to_2d_mat, guaranteeing that it will
* match whatever algorithm produced that one, even if it was produced on a
* different machine with different numerical precision.
*/
INLINE void CollisionBox::
rederive_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const {
to_3d_mat.invert_from(_to_2d_mat[plane]);
}
/** /**
* Extrude the indicated point in the polygon's 2-d definition space back into * Extrude the indicated point in the polygon's 2-d definition space back into
* 3-d coordinates. * 3-d coordinates.
@ -295,11 +271,3 @@ operator = (const CollisionBox::PointDef &copy) {
_p = copy._p; _p = copy._p;
_v = copy._v; _v = copy._v;
} }
/**
* returns the points that form the nth plane
*/
INLINE CollisionBox::Points CollisionBox::
get_plane_points(int n) {
return _points[n];
}

View File

@ -66,14 +66,11 @@ make_copy() {
* Compute parameters for each of the box's sides * Compute parameters for each of the box's sides
*/ */
void CollisionBox:: void CollisionBox::
setup_box(){ setup_box() {
for(int plane = 0; plane < 6; plane++) { assert(sizeof(_points) / sizeof(_points[0]) == 6);
LPoint3 array[4]; assert(sizeof(_points[0]) / sizeof(_points[0][0]) == 4);
array[0] = get_point(plane_def[plane][0]); for (int plane = 0; plane < 6; plane++) {
array[1] = get_point(plane_def[plane][1]); setup_points(plane);
array[2] = get_point(plane_def[plane][2]);
array[3] = get_point(plane_def[plane][3]);
setup_points(array, array+4, plane);
} }
} }
@ -81,11 +78,8 @@ setup_box(){
* Computes the plane and 2d projection of points that make up this side. * Computes the plane and 2d projection of points that make up this side.
*/ */
void CollisionBox:: void CollisionBox::
setup_points(const LPoint3 *begin, const LPoint3 *end, int plane) { setup_points(int plane) {
int num_points = end - begin; PointDef *points = _points[plane];
nassertv(num_points >= 3);
_points[plane].clear();
// Construct a matrix that rotates the points from the (X,0,Z) plane into // Construct a matrix that rotates the points from the (X,0,Z) plane into
// the 3-d plane. // the 3-d plane.
@ -96,32 +90,15 @@ setup_points(const LPoint3 *begin, const LPoint3 *end, int plane) {
_to_2d_mat[plane].invert_from(to_3d_mat); _to_2d_mat[plane].invert_from(to_3d_mat);
// Now project all of the points onto the 2-d plane. // Now project all of the points onto the 2-d plane.
for (size_t i = 0; i < 4; ++i) {
const LPoint3 *pi; LPoint3 point = get_point(plane_def[plane][i]) * _to_2d_mat[plane];
for (pi = begin; pi != end; ++pi) { points[i] = PointDef(point[0], point[2]);
LPoint3 point = (*pi) * _to_2d_mat[plane];
_points[plane].push_back(PointDef(point[0], point[2]));
} }
nassertv(_points[plane].size() >= 3); for (size_t i = 0; i < 4; i++) {
points[i]._v = points[(i + 1) % 4]._p - points[i]._p;
#ifndef NDEBUG points[i]._v.normalize();
/*
// Now make sure the points define a convex polygon.
if (is_concave()) {
collide_cat.error() << "Invalid concave CollisionPolygon defined:\n";
const LPoint3 *pi;
for (pi = begin; pi != end; ++pi) {
collide_cat.error(false) << " " << (*pi) << "\n";
} }
collide_cat.error(false)
<< " normal " << normal << " with length " << normal.length() << "\n";
_points.clear();
}
*/
#endif
compute_vectors(_points[plane]);
} }
/** /**
@ -146,10 +123,6 @@ xform(const LMatrix4 &mat) {
for(int p = 0; p < 6 ; p++) { for(int p = 0; p < 6 ; p++) {
_planes[p] = set_plane(p); _planes[p] = set_plane(p);
} }
_x = _vertex[0].get_x() - _center.get_x();
_y = _vertex[0].get_y() - _center.get_y();
_z = _vertex[0].get_z() - _center.get_z();
_radius = sqrt(_x * _x + _y * _y + _z * _z);
setup_box(); setup_box();
mark_viz_stale(); mark_viz_stale();
mark_internal_bounds_stale(); mark_internal_bounds_stale();
@ -196,7 +169,11 @@ output(std::ostream &out) const {
*/ */
PT(BoundingVolume) CollisionBox:: PT(BoundingVolume) CollisionBox::
compute_internal_bounds() const { compute_internal_bounds() const {
return new BoundingSphere(_center, _radius); PN_stdfloat x = _vertex[0].get_x() - _center.get_x();
PN_stdfloat y = _vertex[0].get_y() - _center.get_y();
PN_stdfloat z = _vertex[0].get_z() - _center.get_z();
PN_stdfloat radius = sqrt(x * x + y * y + z * z);
return new BoundingSphere(_center, radius);
} }
/** /**
@ -233,10 +210,8 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
LVector3 normal; LVector3 normal;
for(ip = 0, intersect = false; ip < 6 && !intersect; ip++) { for(ip = 0, intersect = false; ip < 6 && !intersect; ip++) {
plane = get_plane( ip ); plane = get_plane(ip);
if (_points[ip].size() < 3) {
continue;
}
if (wrt_prev_space != wrt_space) { if (wrt_prev_space != wrt_space) {
// If we have a delta between the previous position and the current // If we have a delta between the previous position and the current
// position, we use that to determine some more properties of the // position, we use that to determine some more properties of the
@ -322,17 +297,17 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
Points new_points; Points new_points;
if (apply_clip_plane(new_points, cpa, entry.get_into_node_path().get_net_transform(),ip)) { if (apply_clip_plane(new_points, cpa, entry.get_into_node_path().get_net_transform(),ip)) {
// All points are behind the clip plane; just do the default test. // All points are behind the clip plane; just do the default test.
edge_dist = dist_to_polygon(p, _points[ip]); edge_dist = dist_to_polygon(p, _points[ip], 4);
} else if (new_points.empty()) { } else if (new_points.empty()) {
// The polygon is completely clipped. // The polygon is completely clipped.
continue; continue;
} else { } else {
// Test against the clipped polygon. // Test against the clipped polygon.
edge_dist = dist_to_polygon(p, new_points); edge_dist = dist_to_polygon(p, new_points.data(), new_points.size());
} }
} else { } else {
// No clip plane is in effect. Do the default test. // No clip plane is in effect. Do the default test.
edge_dist = dist_to_polygon(p, _points[ip]); edge_dist = dist_to_polygon(p, _points[ip], 4);
} }
max_dist = from_radius; max_dist = from_radius;
@ -1129,13 +1104,13 @@ apply_clip_plane(CollisionBox::Points &new_points,
LPlane plane = plane_node->get_plane() * new_transform->get_mat(); LPlane plane = plane_node->get_plane() * new_transform->get_mat();
if (first_plane) { if (first_plane) {
first_plane = false; first_plane = false;
if (!clip_polygon(new_points, _points[plane_no], plane, plane_no)) { if (!clip_polygon(new_points, _points[plane_no], 4, plane, plane_no)) {
all_in = false; all_in = false;
} }
} else { } else {
Points last_points; Points last_points;
last_points.swap(new_points); last_points.swap(new_points);
if (!clip_polygon(new_points, last_points, plane, plane_no)) { if (!clip_polygon(new_points, last_points.data(), last_points.size(), plane, plane_no)) {
all_in = false; all_in = false;
} }
} }
@ -1158,10 +1133,10 @@ apply_clip_plane(CollisionBox::Points &new_points,
*/ */
bool CollisionBox:: bool CollisionBox::
clip_polygon(CollisionBox::Points &new_points, clip_polygon(CollisionBox::Points &new_points,
const CollisionBox::Points &source_points, const PointDef *source_points, size_t num_source_points,
const LPlane &plane, int plane_no) const { const LPlane &plane, int plane_no) const {
new_points.clear(); new_points.clear();
if (source_points.empty()) { if (num_source_points == 0) {
return true; return true;
} }
@ -1173,7 +1148,7 @@ clip_polygon(CollisionBox::Points &new_points,
if (plane.dist_to_plane(get_plane(plane_no).get_point()) < 0.0) { if (plane.dist_to_plane(get_plane(plane_no).get_point()) < 0.0) {
// A point within the polygon is behind the clipping plane: the polygon // A point within the polygon is behind the clipping plane: the polygon
// is all in. // is all in.
new_points = source_points; new_points.insert(new_points.end(), source_points, source_points + num_source_points);
return true; return true;
} }
return false; return false;
@ -1194,14 +1169,13 @@ clip_polygon(CollisionBox::Points &new_points,
// We might increase the number of vertices by as many as 1, if the plane // We might increase the number of vertices by as many as 1, if the plane
// clips off exactly one corner. (We might also decrease the number of // clips off exactly one corner. (We might also decrease the number of
// vertices, or keep them the same number.) // vertices, or keep them the same number.)
new_points.reserve(source_points.size() + 1); new_points.reserve(num_source_points + 1);
LPoint2 last_point = source_points.back()._p; LPoint2 last_point = source_points[num_source_points - 1]._p;
bool last_is_in = !is_right(last_point - from2d, delta2d); bool last_is_in = !is_right(last_point - from2d, delta2d);
bool all_in = last_is_in; bool all_in = last_is_in;
Points::const_iterator pi; for (size_t pi = 0; pi < num_source_points; ++pi) {
for (pi = source_points.begin(); pi != source_points.end(); ++pi) { const LPoint2 &this_point = source_points[pi]._p;
const LPoint2 &this_point = (*pi)._p;
bool this_is_in = !is_right(this_point - from2d, delta2d); bool this_is_in = !is_right(this_point - from2d, delta2d);
// There appears to be a compiler bug in gcc 4.0: we need to extract this // There appears to be a compiler bug in gcc 4.0: we need to extract this
@ -1234,15 +1208,13 @@ clip_polygon(CollisionBox::Points &new_points,
return all_in; return all_in;
} }
/** /**
* Returns the linear distance from the 2-d point to the nearest part of the * Returns the linear distance from the 2-d point to the nearest part of the
* polygon defined by the points vector. The result is negative if the point * polygon defined by the points vector. The result is negative if the point
* is within the polygon. * is within the polygon.
*/ */
PN_stdfloat CollisionBox:: PN_stdfloat CollisionBox::
dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const { dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const {
// We know that that the polygon is convex and is defined with the points in // We know that that the polygon is convex and is defined with the points in
// counterclockwise order. Therefore, we simply compare the signed distance // counterclockwise order. Therefore, we simply compare the signed distance
// to each line segment; we ignore any negative values, and take the minimum // to each line segment; we ignore any negative values, and take the minimum
@ -1254,10 +1226,9 @@ dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const {
bool got_dist = false; bool got_dist = false;
PN_stdfloat best_dist = -1.0f; PN_stdfloat best_dist = -1.0f;
size_t num_points = points.size();
for (size_t i = 0; i < num_points - 1; ++i) { for (size_t i = 0; i < num_points - 1; ++i) {
PN_stdfloat d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p, PN_stdfloat d = dist_to_line_segment(p, points[i]._p, points[i + 1]._p,
points[i]._v); points[i]._v);
if (d >= 0.0f) { if (d >= 0.0f) {
if (!got_dist || d < best_dist) { if (!got_dist || d < best_dist) {
best_dist = d; best_dist = d;
@ -1267,7 +1238,7 @@ dist_to_polygon(const LPoint2 &p, const CollisionBox::Points &points) const {
} }
PN_stdfloat d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p, PN_stdfloat d = dist_to_line_segment(p, points[num_points - 1]._p, points[0]._p,
points[num_points - 1]._v); points[num_points - 1]._v);
if (d >= 0.0f) { if (d >= 0.0f) {
if (!got_dist || d < best_dist) { if (!got_dist || d < best_dist) {
best_dist = d; best_dist = d;
@ -1450,10 +1421,14 @@ write_datagram(BamWriter *manager, Datagram &me) {
for(int i=0; i < 8; i++) { for(int i=0; i < 8; i++) {
_vertex[i].write_datagram(me); _vertex[i].write_datagram(me);
} }
me.add_stdfloat(_radius); PN_stdfloat x = _vertex[0].get_x() - _center.get_x();
me.add_stdfloat(_x); PN_stdfloat y = _vertex[0].get_y() - _center.get_y();
me.add_stdfloat(_y); PN_stdfloat z = _vertex[0].get_z() - _center.get_z();
me.add_stdfloat(_z); PN_stdfloat radius = sqrt(x * x + y * y + z * z);
me.add_stdfloat(radius);
me.add_stdfloat(x);
me.add_stdfloat(y);
me.add_stdfloat(z);
for(int i=0; i < 6; i++) { for(int i=0; i < 6; i++) {
_planes[i].write_datagram(me); _planes[i].write_datagram(me);
} }
@ -1461,8 +1436,8 @@ write_datagram(BamWriter *manager, Datagram &me) {
_to_2d_mat[i].write_datagram(me); _to_2d_mat[i].write_datagram(me);
} }
for(int i=0; i < 6; i++) { for(int i=0; i < 6; i++) {
me.add_uint16(_points[i].size()); me.add_uint16(4);
for (size_t j = 0; j < _points[i].size(); j++) { for (size_t j = 0; j < 4; j++) {
_points[i][j]._p.write_datagram(me); _points[i][j]._p.write_datagram(me);
_points[i][j]._v.write_datagram(me); _points[i][j]._v.write_datagram(me);
} }
@ -1497,10 +1472,10 @@ fillin(DatagramIterator& scan, BamReader* manager) {
for(int i=0; i < 8; i++) { for(int i=0; i < 8; i++) {
_vertex[i].read_datagram(scan); _vertex[i].read_datagram(scan);
} }
_radius = scan.get_stdfloat(); scan.get_stdfloat();
_x = scan.get_stdfloat(); scan.get_stdfloat();
_y = scan.get_stdfloat(); scan.get_stdfloat();
_z = scan.get_stdfloat(); scan.get_stdfloat();
for(int i=0; i < 6; i++) { for(int i=0; i < 6; i++) {
_planes[i].read_datagram(scan); _planes[i].read_datagram(scan);
} }
@ -1509,12 +1484,10 @@ fillin(DatagramIterator& scan, BamReader* manager) {
} }
for(int i=0; i < 6; i++) { for(int i=0; i < 6; i++) {
size_t size = scan.get_uint16(); size_t size = scan.get_uint16();
nassertv(size == 4);
for (size_t j = 0; j < size; j++) { for (size_t j = 0; j < size; j++) {
LPoint2 p; _points[i][j]._p.read_datagram(scan);
LVector2 v; _points[i][j]._v.read_datagram(scan);
p.read_datagram(scan);
v.read_datagram(scan);
_points[i].push_back(PointDef(p, v));
} }
} }
} }

View File

@ -99,7 +99,6 @@ private:
LPoint3 _center; LPoint3 _center;
LPoint3 _min; LPoint3 _min;
LPoint3 _max; LPoint3 _max;
PN_stdfloat _x, _y, _z, _radius;
LPoint3 _vertex[8]; // Each of the Eight Vertices of the Box LPoint3 _vertex[8]; // Each of the Eight Vertices of the Box
LPlane _planes[6]; //Points to each of the six sides of the Box LPlane _planes[6]; //Points to each of the six sides of the Box
@ -119,6 +118,7 @@ private:
public: public:
class PointDef { class PointDef {
public: public:
PointDef() = default;
INLINE PointDef(const LPoint2 &p, const LVector2 &v); INLINE PointDef(const LPoint2 &p, const LVector2 &v);
INLINE PointDef(PN_stdfloat x, PN_stdfloat y); INLINE PointDef(PN_stdfloat x, PN_stdfloat y);
INLINE PointDef(const PointDef &copy); INLINE PointDef(const PointDef &copy);
@ -134,25 +134,22 @@ public:
const Points &points) const; const Points &points) const;
bool point_is_inside(const LPoint2 &p, const Points &points) const; bool point_is_inside(const LPoint2 &p, const Points &points) const;
PN_stdfloat dist_to_polygon(const LPoint2 &p, const Points &points) const; PN_stdfloat dist_to_polygon(const LPoint2 &p, const PointDef *points, size_t num_points) const;
void setup_points(const LPoint3 *begin, const LPoint3 *end, int plane); void setup_points(int plane);
INLINE LPoint2 to_2d(const LVecBase3 &point3d, int plane) const; INLINE LPoint2 to_2d(const LVecBase3 &point3d, int plane) const;
INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const; INLINE void calc_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const;
INLINE void rederive_to_3d_mat(LMatrix4 &to_3d_mat, int plane) const;
INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat); INLINE static LPoint3 to_3d(const LVecBase2 &point2d, const LMatrix4 &to_3d_mat);
bool clip_polygon(Points &new_points, const Points &source_points, bool clip_polygon(Points &new_points, const PointDef *source_points,
const LPlane &plane,int plane_no) const; size_t num_source_points, const LPlane &plane,
int plane_no) const;
bool apply_clip_plane(Points &new_points, const ClipPlaneAttrib *cpa, bool apply_clip_plane(Points &new_points, const ClipPlaneAttrib *cpa,
const TransformState *net_transform, int plane_no) const; const TransformState *net_transform, int plane_no) const;
private: private:
Points _points[6]; // one set of points for each of the six planes that make up the box PointDef _points[6][4]; // one set of points for each of the six planes that make up the box
LMatrix4 _to_2d_mat[6]; LMatrix4 _to_2d_mat[6];
public:
INLINE Points get_plane_points( int n );
public: public:
static void register_with_read_factory(); static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &me); virtual void write_datagram(BamWriter *manager, Datagram &me);