Skip to content

Commit fe9e752

Browse files
committed
Implement box-into-box collision test, and fix a scaling issue with box-into-plane
1 parent f7b61d4 commit fe9e752

File tree

2 files changed

+155
-12
lines changed

2 files changed

+155
-12
lines changed

panda/src/collide/collisionBox.cxx

Lines changed: 147 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -619,18 +619,161 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
619619
return new_entry;
620620
}
621621

622-
623622
////////////////////////////////////////////////////////////////////
624623
// Function: CollisionBox::test_intersection_from_box
625624
// Access: Public, Virtual
626625
// Description: Double dispatch point for box as a FROM object
627-
// NOT Implemented.
628626
////////////////////////////////////////////////////////////////////
629627
PT(CollisionEntry) CollisionBox::
630628
test_intersection_from_box(const CollisionEntry &entry) const {
631-
return NULL;
632-
}
629+
const CollisionBox *box;
630+
DCAST_INTO_R(box, entry.get_from(), 0);
631+
632+
const LMatrix4 &wrt_mat = entry.get_wrt_mat();
633+
634+
LPoint3 diff = wrt_mat.xform_point_general(box->get_center()) - _center;
635+
LVector3 from_extents = box->get_dimensions() * 0.5f;
636+
LVector3 into_extents = get_dimensions() * 0.5f;
637+
638+
LVecBase3 box_x = wrt_mat.get_row3(0);
639+
LVecBase3 box_y = wrt_mat.get_row3(1);
640+
LVecBase3 box_z = wrt_mat.get_row3(2);
641+
642+
// To make the math simpler, normalize the box basis vectors, instead
643+
// applying the scale to the box dimensions. Note that this doesn't
644+
// work for a non-uniform scales applied after a rotation, since that
645+
// has the possibility of making the box no longer a box.
646+
PN_stdfloat l;
647+
l = box_x.length();
648+
from_extents[0] *= l;
649+
box_x /= l;
650+
l = box_y.length();
651+
from_extents[1] *= l;
652+
box_y /= l;
653+
l = box_z.length();
654+
from_extents[2] *= l;
655+
box_z /= l;
656+
657+
PN_stdfloat r1, r2;
658+
659+
// SAT test for the three axes of the into cube.
660+
r1 = into_extents[0];
661+
r2 = cabs(box_x[0] * from_extents[0]) +
662+
cabs(box_y[0] * from_extents[1]) +
663+
cabs(box_z[0] * from_extents[2]);
664+
if (cabs(diff[0]) > r1 + r2) {
665+
return NULL;
666+
}
667+
668+
r1 = into_extents[1];
669+
r2 = cabs(box_x[1] * from_extents[0]) +
670+
cabs(box_y[1] * from_extents[1]) +
671+
cabs(box_z[1] * from_extents[2]);
672+
if (cabs(diff[1]) > r1 + r2) {
673+
return NULL;
674+
}
675+
676+
r1 = into_extents[2];
677+
r2 = cabs(box_x[2] * from_extents[0]) +
678+
cabs(box_y[2] * from_extents[1]) +
679+
cabs(box_z[2] * from_extents[2]);
680+
if (cabs(diff[2]) > r1 + r2) {
681+
return NULL;
682+
}
683+
684+
// SAT test for the three axes of the from cube.
685+
r1 = cabs(box_x[0] * into_extents[0]) +
686+
cabs(box_x[1] * into_extents[1]) +
687+
cabs(box_x[2] * into_extents[2]);
688+
r2 = from_extents[0];
689+
if (cabs(diff.dot(box_x)) > r1 + r2) {
690+
return NULL;
691+
}
692+
693+
r1 = cabs(box_y[0] * into_extents[0]) +
694+
cabs(box_y[1] * into_extents[1]) +
695+
cabs(box_y[2] * into_extents[2]);
696+
r2 = from_extents[1];
697+
if (cabs(diff.dot(box_y)) > r1 + r2) {
698+
return NULL;
699+
}
700+
701+
r1 = cabs(box_z[0] * into_extents[0]) +
702+
cabs(box_z[1] * into_extents[1]) +
703+
cabs(box_z[2] * into_extents[2]);
704+
r2 = from_extents[2];
705+
if (cabs(diff.dot(box_z)) > r1 + r2) {
706+
return NULL;
707+
}
708+
709+
// SAT test of the nine cross products.
710+
r1 = into_extents[1] * cabs(box_x[2]) + into_extents[2] * cabs(box_x[1]);
711+
r2 = from_extents[1] * cabs(box_z[0]) + from_extents[2] * cabs(box_y[0]);
712+
if (cabs(diff[2] * box_x[1] - diff[1] * box_x[2]) > r1 + r2) {
713+
return NULL;
714+
}
715+
716+
r1 = into_extents[1] * cabs(box_y[2]) + into_extents[2] * cabs(box_y[1]);
717+
r2 = from_extents[0] * cabs(box_z[0]) + from_extents[2] * cabs(box_x[0]);
718+
if (cabs(diff[2] * box_y[1] - diff[1] * box_y[2]) > r1 + r2) {
719+
return NULL;
720+
}
633721

722+
r1 = into_extents[1] * cabs(box_z[2]) + into_extents[2] * cabs(box_z[1]);
723+
r2 = from_extents[0] * cabs(box_y[0]) + from_extents[1] * cabs(box_x[0]);
724+
if (cabs(diff[2] * box_z[1] - diff[1] * box_z[2]) > r1 + r2) {
725+
return NULL;
726+
}
727+
728+
r1 = into_extents[0] * cabs(box_x[2]) + into_extents[2] * cabs(box_x[0]);
729+
r2 = from_extents[1] * cabs(box_z[1]) + from_extents[2] * cabs(box_y[1]);
730+
if (cabs(diff[0] * box_x[2] - diff[2] * box_x[0]) > r1 + r2) {
731+
return NULL;
732+
}
733+
734+
r1 = into_extents[0] * cabs(box_y[2]) + into_extents[2] * cabs(box_y[0]);
735+
r2 = from_extents[0] * cabs(box_z[1]) + from_extents[2] * cabs(box_x[1]);
736+
if (cabs(diff[0] * box_y[2] - diff[2] * box_y[0]) > r1 + r2) {
737+
return NULL;
738+
}
739+
740+
r1 = into_extents[0] * cabs(box_z[2]) + into_extents[2] * cabs(box_z[0]);
741+
r2 = from_extents[0] * cabs(box_y[1]) + from_extents[1] * cabs(box_x[1]);
742+
if (cabs(diff[0] * box_z[2] - diff[2] * box_z[0]) > r1 + r2) {
743+
return NULL;
744+
}
745+
746+
r1 = into_extents[0] * cabs(box_x[1]) + into_extents[1] * cabs(box_x[0]);
747+
r2 = from_extents[1] * cabs(box_z[2]) + from_extents[2] * cabs(box_y[2]);
748+
if (cabs(diff[1] * box_x[0] - diff[0] * box_x[1]) > r1 + r2) {
749+
return NULL;
750+
}
751+
752+
r1 = into_extents[0] * cabs(box_y[1]) + into_extents[1] * cabs(box_y[0]);
753+
r2 = from_extents[0] * cabs(box_z[2]) + from_extents[2] * cabs(box_x[2]);
754+
if (cabs(diff[1] * box_y[0] - diff[0] * box_y[1]) > r1 + r2) {
755+
return NULL;
756+
}
757+
758+
r1 = into_extents[0] * cabs(box_z[1]) + into_extents[1] * cabs(box_z[0]);
759+
r2 = from_extents[0] * cabs(box_y[2]) + from_extents[1] * cabs(box_x[2]);
760+
if (cabs(diff[1] * box_z[0] - diff[0] * box_z[1]) > r1 + r2) {
761+
return NULL;
762+
}
763+
764+
if (collide_cat.is_debug()) {
765+
collide_cat.debug()
766+
<< "intersection detected from " << entry.get_from_node_path()
767+
<< " into " << entry.get_into_node_path() << "\n";
768+
}
769+
PT(CollisionEntry) new_entry = new CollisionEntry(entry);
770+
771+
if (has_effective_normal() && box->get_respect_effective_normal()) {
772+
new_entry->set_surface_normal(get_effective_normal());
773+
}
774+
775+
return new_entry;
776+
}
634777

635778
////////////////////////////////////////////////////////////////////
636779
// Function: CollisionBox::fill_viz_geom

panda/src/collide/collisionPlane.cxx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -405,17 +405,17 @@ test_intersection_from_box(const CollisionEntry &entry) const {
405405
const LMatrix4 &wrt_mat = entry.get_wrt_mat();
406406

407407
LPoint3 from_center = box->get_center() * wrt_mat;
408-
LVector3 from_extents = box->get_dimensions() * wrt_mat * 0.5;
408+
LVector3 from_extents = box->get_dimensions() * 0.5f;
409409
PN_stdfloat dist = _plane.dist_to_plane(from_center);
410410

411-
LVecBase3 box_x = entry.get_wrt_mat().get_row3(0);
412-
LVecBase3 box_y = entry.get_wrt_mat().get_row3(1);
413-
LVecBase3 box_z = entry.get_wrt_mat().get_row3(2);
411+
LVecBase3 box_x = wrt_mat.get_row3(0);
412+
LVecBase3 box_y = wrt_mat.get_row3(1);
413+
LVecBase3 box_z = wrt_mat.get_row3(2);
414414

415-
if (abs(dist) >
416-
abs(box_x.dot(_plane.get_normal()) * from_extents[0]) +
417-
abs(box_y.dot(_plane.get_normal()) * from_extents[1]) +
418-
abs(box_z.dot(_plane.get_normal()) * from_extents[2])) {
415+
if (cabs(dist) >
416+
cabs(box_x.dot(_plane.get_normal()) * from_extents[0]) +
417+
cabs(box_y.dot(_plane.get_normal()) * from_extents[1]) +
418+
cabs(box_z.dot(_plane.get_normal()) * from_extents[2])) {
419419
// No collision.
420420
return NULL;
421421
}

0 commit comments

Comments
 (0)