40 "Collision Volumes:CollisionSphere");
42 "Collision Tests:CollisionSphere");
58 return entry.
get_into()->test_intersection_from_sphere(entry);
64 void CollisionSphere::
65 xform(
const LMatrix4 &mat) {
66 _center = _center * mat;
70 LVector3 radius_v = LVector3(_radius, 0.0f, 0.0f) * mat;
71 _radius = length(radius_v);
73 mark_internal_bounds_stale();
92 return _volume_pcollector;
101 return _test_pcollector;
107 void CollisionSphere::
108 output(std::ostream &out)
const {
109 out <<
"sphere, c (" << get_center() <<
"), r " << get_radius();
116 compute_internal_bounds()
const {
124 test_intersection_from_sphere(
const CollisionEntry &entry)
const {
126 DCAST_INTO_R(sphere, entry.
get_from(),
nullptr);
130 const LMatrix4 &wrt_mat = wrt_space->get_mat();
132 LPoint3 from_b = sphere->get_center() * wrt_mat;
134 LPoint3 into_center(get_center());
135 PN_stdfloat into_radius(get_radius());
137 LVector3 from_radius_v =
138 LVector3(sphere->get_radius(), 0.0f, 0.0f) * wrt_mat;
139 PN_stdfloat from_radius = length(from_radius_v);
141 LPoint3 into_intersection_point(from_b);
143 LPoint3 contact_point(into_intersection_point);
144 PN_stdfloat actual_t = 0.0f;
146 LVector3 vec = from_b - into_center;
147 PN_stdfloat dist2 = dot(vec, vec);
148 if (dist2 > (into_radius + from_radius) * (into_radius + from_radius)) {
152 LPoint3 from_a = sphere->get_center() * wrt_prev_space->get_mat();
154 if (!from_a.almost_equal(from_b)) {
155 LVector3 from_direction = from_b - from_a;
156 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
161 if (t2 < 0.0 || t1 > 1.0) {
168 actual_t = min(1.0, max(0.0, t1));
169 contact_point = from_a + actual_t * (from_b - from_a);
174 into_intersection_point = from_a;
178 into_intersection_point = from_a + t1 * from_direction;
186 if (collide_cat.is_debug()) {
193 LPoint3 from_center = sphere->get_center() * wrt_mat;
195 LVector3 surface_normal;
196 LVector3 v(into_intersection_point - into_center);
197 PN_stdfloat vec_length = v.length();
198 if (IS_NEARLY_ZERO(vec_length)) {
202 surface_normal.set(1.0, 0.0, 0.0);
204 surface_normal = v / vec_length;
209 LVector3 contact_normal;
210 LVector3 v2 = contact_point - into_center;
211 PN_stdfloat v2_len = v2.length();
212 if (IS_NEARLY_ZERO(v2_len)) {
216 contact_normal.set(1.0, 0.0, 0.0);
218 contact_normal = v2 / v2_len;
221 new_entry->set_surface_normal(eff_normal);
222 new_entry->set_surface_point(into_center + surface_normal * into_radius);
223 new_entry->set_interior_point(from_center - surface_normal * from_radius);
224 new_entry->set_contact_pos(contact_point);
225 new_entry->set_contact_normal(contact_normal);
226 new_entry->set_t(actual_t);
237 DCAST_INTO_R(line, entry.
get_from(),
nullptr);
239 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
241 LPoint3 from_origin = line->get_origin() * wrt_mat;
242 LVector3 from_direction = line->get_direction() * wrt_mat;
245 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
250 if (collide_cat.is_debug()) {
257 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
258 new_entry->set_surface_point(into_intersection_point);
263 LVector3 normal = into_intersection_point - get_center();
265 new_entry->set_surface_normal(normal);
277 DCAST_INTO_R(box, entry.
get_from(),
nullptr);
281 const LMatrix4 &wrt_mat = entry.get_inv_wrt_mat();
283 LPoint3 center = wrt_mat.xform_point(_center);
284 PN_stdfloat radius_sq = wrt_mat.xform_vec(LVector3(0, 0, _radius)).length_squared();
286 LPoint3 box_min = box->get_min();
287 LPoint3 box_max = box->get_max();
293 if (center[0] < box_min[0]) {
294 s = center[0] - box_min[0];
297 }
else if (center[0] > box_max[0]) {
298 s = center[0] - box_max[0];
302 if (center[1] < box_min[1]) {
303 s = center[1] - box_min[1];
306 }
else if (center[1] > box_max[1]) {
307 s = center[1] - box_max[1];
311 if (center[2] < box_min[2]) {
312 s = center[2] - box_min[2];
315 }
else if (center[2] > box_max[2]) {
316 s = center[2] - box_max[2];
324 if (collide_cat.is_debug()) {
333 LPoint3 interior = entry.get_wrt_mat().xform_point(center.fmax(box_min).fmin(box_max));
334 new_entry->set_interior_point(interior);
337 LVector3 normal = interior - _center;
339 new_entry->set_surface_point(_center + normal * _radius);
340 new_entry->set_surface_normal(
353 DCAST_INTO_R(ray, entry.
get_from(),
nullptr);
355 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
357 LPoint3 from_origin = ray->get_origin() * wrt_mat;
358 LVector3 from_direction = ray->get_direction() * wrt_mat;
361 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
373 if (collide_cat.is_debug()) {
380 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
381 new_entry->set_surface_point(into_intersection_point);
386 LVector3 normal = into_intersection_point - get_center();
388 new_entry->set_surface_normal(normal);
398 test_intersection_from_segment(
const CollisionEntry &entry)
const {
400 DCAST_INTO_R(segment, entry.
get_from(),
nullptr);
402 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
404 LPoint3 from_a = segment->get_point_a() * wrt_mat;
405 LPoint3 from_b = segment->get_point_b() * wrt_mat;
406 LVector3 from_direction = from_b - from_a;
409 if (!intersects_line(t1, t2, from_a, from_direction, 0.0f)) {
414 if (t2 < 0.0 || t1 > 1.0) {
422 if (collide_cat.is_debug()) {
429 LPoint3 into_intersection_point = from_a + t1 * from_direction;
430 new_entry->set_surface_point(into_intersection_point);
435 LVector3 normal = into_intersection_point - get_center();
437 new_entry->set_surface_normal(normal);
447 test_intersection_from_capsule(
const CollisionEntry &entry)
const {
449 DCAST_INTO_R(capsule, entry.
get_from(),
nullptr);
451 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
453 LPoint3 from_a = capsule->get_point_a() * wrt_mat;
454 LPoint3 from_b = capsule->get_point_b() * wrt_mat;
455 LVector3 from_direction = from_b - from_a;
457 LVector3 from_radius_v =
458 LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat;
459 PN_stdfloat from_radius = length(from_radius_v);
462 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
467 if (t2 < 0.0 || t1 > 1.0) {
473 PN_stdfloat t = (t1 + t2) * (PN_stdfloat)0.5;
474 t = max(t, (PN_stdfloat)0.0);
475 t = min(t, (PN_stdfloat)1.0);
476 LPoint3 inner_point = from_a + t * from_direction;
478 if (collide_cat.is_debug()) {
485 LVector3 normal = inner_point - get_center();
487 new_entry->set_surface_point(get_center() + normal * get_radius());
488 new_entry->set_interior_point(inner_point - normal * from_radius);
493 new_entry->set_surface_normal(normal);
503 test_intersection_from_parabola(
const CollisionEntry &entry)
const {
505 DCAST_INTO_R(parabola, entry.
get_from(),
nullptr);
507 const LMatrix4 &wrt_mat = entry.get_wrt_mat();
511 local_p.xform(wrt_mat);
514 if (!intersects_parabola(t, local_p, parabola->
get_t1(), parabola->
get_t2(),
515 local_p.calc_point(parabola->
get_t1()),
516 local_p.calc_point(parabola->
get_t2()))) {
521 if (collide_cat.is_debug()) {
528 LPoint3 into_intersection_point = local_p.calc_point(t);
529 new_entry->set_surface_point(into_intersection_point);
534 LVector3 normal = into_intersection_point - get_center();
536 new_entry->set_surface_normal(normal);
546 void CollisionSphere::
548 if (collide_cat.is_debug()) {
550 <<
"Recomputing viz for " << *
this <<
"\n";
553 static const int num_slices = 16;
554 static const int num_stacks = 8;
562 for (
int sl = 0; sl < num_slices; ++sl) {
563 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
564 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
565 vertex.add_data3(compute_point(0.0, longitude0));
566 for (
int st = 1; st < num_stacks; ++st) {
567 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
568 vertex.add_data3(compute_point(latitude, longitude0));
569 vertex.add_data3(compute_point(latitude, longitude1));
571 vertex.add_data3(compute_point(1.0, longitude0));
573 strip->add_next_vertices(num_stacks * 2);
574 strip->close_primitive();
578 geom->add_primitive(strip);
580 _viz_geom->add_geom(geom, get_solid_viz_state());
581 _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
592 bool CollisionSphere::
593 intersects_line(
double &t1,
double &t2,
594 const LPoint3 &from,
const LVector3 &delta,
595 PN_stdfloat inflate_radius)
const {
621 double A = dot(delta, delta);
623 nassertr(A != 0.0,
false);
625 LVector3 fc = from - get_center();
626 double B = 2.0f* dot(delta, fc);
627 double fc_d2 = dot(fc, fc);
628 double radius = get_radius() + inflate_radius;
629 double C = fc_d2 - radius * radius;
631 double radical = B*B - 4.0*A*C;
633 if (IS_NEARLY_ZERO(radical)) {
635 t1 = t2 = -B /(2.0*A);
638 }
else if (radical < 0.0) {
643 double reciprocal_2A = 1.0/(2.0*A);
644 double sqrt_radical = sqrtf(radical);
645 t1 = ( -B - sqrt_radical ) * reciprocal_2A;
646 t2 = ( -B + sqrt_radical ) * reciprocal_2A;
659 bool CollisionSphere::
660 intersects_parabola(
double &t,
const LParabola ¶bola,
661 double t1,
double t2,
662 const LPoint3 &p1,
const LPoint3 &p2)
const {
665 if ((p1 - _center).length_squared() > _radius * _radius) {
683 double tmid = (t1 + t2) * 0.5;
684 if (tmid != t1 && tmid != t2) {
685 LPoint3 pmid = parabola.calc_point(tmid);
686 LPoint3 pmid2 = (p1 + p2) * 0.5f;
688 if ((pmid - pmid2).length_squared() > 0.001f) {
690 if (intersects_parabola(t, parabola, t1, tmid, p1, pmid)) {
693 return intersects_parabola(t, parabola, tmid, t2, pmid, p2);
699 if (!intersects_line(t1a, t2a, p1, p2 - p1, 0.0f)) {
703 if (t2a < 0.0 || t1a > 1.0) {
716 LVertex CollisionSphere::
717 compute_point(PN_stdfloat latitude, PN_stdfloat longitude)
const {
719 csincos(latitude * MathNumbers::pi, &s1, &c1);
722 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
724 LVertex p(s1 * c2, s1 * s2, c1);
725 return p * get_radius() + get_center();
743 _center.write_datagram(me);
757 me->fillin(scan, manager);
766 void CollisionSphere::
768 CollisionSolid::fillin(scan, manager);
769 _center.read_datagram(scan);
get_t2
Returns the ending point on the parabola.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const LVector3 & get_effective_normal() const
Returns the normal that was set by set_effective_normal().
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
An infinite ray, with a specific origin and direction.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static void register_with_read_factory()
Factory method to generate a CollisionSphere object.
The abstract base class for all things that can collide with other things in the world,...
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
This defines a bounding sphere, consisting of a center and a radius.
A cuboid collision volume or object.
Base class for objects that can be written to and read from Bam files.
get_parabola
Returns the parabola specified by this solid.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of triangle strips.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
A spherical collision volume or object.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
get_respect_effective_normal
See set_respect_effective_normal().
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
get_t1
Returns the starting point on the parabola.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
A finite line segment, with two specific endpoints but no thickness.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a single collision event.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This implements a solid consisting of a cylinder with hemispherical endcaps, also known as a capsule ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
PT(CollisionEntry) CollisionSphere
Transforms the solid by the indicated matrix.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An infinite line, similar to a CollisionRay, except that it extends in both directions.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
This defines a parabolic arc, or subset of an arc, similar to the path of a projectile or falling obj...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_effective_normal() const
Returns true if a special normal was set by set_effective_normal(), false otherwise.
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.