40 "Collision Volumes:CollisionSphere");
42 "Collision Tests:CollisionSphere");
50 return new CollisionSphere(*
this);
58 return entry.
get_into()->test_intersection_from_sphere(entry);
65xform(
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;
107void CollisionSphere::
108output(std::ostream &out)
const {
109 out <<
"sphere, c (" << get_center() <<
"), r " << get_radius();
116compute_internal_bounds()
const {
117 return new BoundingSphere(_center, _radius);
125 const CollisionSphere *sphere;
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()) {
191 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
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);
236 const CollisionLine *line;
237 DCAST_INTO_R(line, entry.
get_from(),
nullptr);
240 const LMatrix4 &wrt_mat = wrt_space->get_mat();
242 LPoint3 from_origin = line->get_origin() * wrt_mat;
243 LVector3 from_direction = line->get_direction() * wrt_mat;
246 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
251 if (collide_cat.is_debug()) {
256 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
258 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
259 new_entry->set_surface_point(into_intersection_point);
264 LVector3 normal = into_intersection_point - get_center();
266 new_entry->set_surface_normal(normal);
277 const CollisionBox *box;
278 DCAST_INTO_R(box, entry.
get_from(),
nullptr);
283 const LMatrix4 &inv_wrt_mat = inv_wrt_space->get_mat();
285 LPoint3 center = inv_wrt_mat.xform_point(_center);
286 PN_stdfloat radius_sq = inv_wrt_mat.xform_vec(LVector3(0, 0, _radius)).length_squared();
288 LPoint3 box_min = box->get_min();
289 LPoint3 box_max = box->get_max();
295 if (center[0] < box_min[0]) {
296 s = center[0] - box_min[0];
299 }
else if (center[0] > box_max[0]) {
300 s = center[0] - box_max[0];
304 if (center[1] < box_min[1]) {
305 s = center[1] - box_min[1];
308 }
else if (center[1] > box_max[1]) {
309 s = center[1] - box_max[1];
313 if (center[2] < box_min[2]) {
314 s = center[2] - box_min[2];
317 }
else if (center[2] > box_max[2]) {
318 s = center[2] - box_max[2];
326 if (collide_cat.is_debug()) {
332 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
336 LPoint3 interior = wrt_space->get_mat().xform_point(center.fmax(box_min).fmin(box_max));
337 new_entry->set_interior_point(interior);
340 LVector3 normal = interior - _center;
342 new_entry->set_surface_point(_center + normal * _radius);
343 new_entry->set_surface_normal(
355 const CollisionRay *ray;
356 DCAST_INTO_R(ray, entry.
get_from(),
nullptr);
359 const LMatrix4 &wrt_mat = wrt_space->get_mat();
361 LPoint3 from_origin = ray->get_origin() * wrt_mat;
362 LVector3 from_direction = ray->get_direction() * wrt_mat;
365 if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
377 if (collide_cat.is_debug()) {
382 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
384 LPoint3 into_intersection_point = from_origin + t1 * from_direction;
385 new_entry->set_surface_point(into_intersection_point);
390 LVector3 normal = into_intersection_point - get_center();
392 new_entry->set_surface_normal(normal);
402test_intersection_from_segment(
const CollisionEntry &entry)
const {
403 const CollisionSegment *segment;
404 DCAST_INTO_R(segment, entry.
get_from(),
nullptr);
407 const LMatrix4 &wrt_mat = wrt_space->get_mat();
409 LPoint3 from_a = segment->get_point_a() * wrt_mat;
410 LPoint3 from_b = segment->get_point_b() * wrt_mat;
411 LVector3 from_direction = from_b - from_a;
414 if (!intersects_line(t1, t2, from_a, from_direction, 0.0f)) {
419 if (t2 < 0.0 || t1 > 1.0) {
427 if (collide_cat.is_debug()) {
432 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
434 LPoint3 into_intersection_point = from_a + t1 * from_direction;
435 new_entry->set_surface_point(into_intersection_point);
440 LVector3 normal = into_intersection_point - get_center();
442 new_entry->set_surface_normal(normal);
452test_intersection_from_capsule(
const CollisionEntry &entry)
const {
453 const CollisionCapsule *capsule;
454 DCAST_INTO_R(capsule, entry.
get_from(),
nullptr);
457 const LMatrix4 &wrt_mat = wrt_space->get_mat();
459 LPoint3 from_a = capsule->get_point_a() * wrt_mat;
460 LPoint3 from_b = capsule->get_point_b() * wrt_mat;
461 LVector3 from_direction = from_b - from_a;
463 LVector3 from_radius_v =
464 LVector3(capsule->get_radius(), 0.0f, 0.0f) * wrt_mat;
465 PN_stdfloat from_radius = length(from_radius_v);
468 if (!intersects_line(t1, t2, from_a, from_direction, from_radius)) {
473 if (t2 < 0.0 || t1 > 1.0) {
479 PN_stdfloat t = (t1 + t2) * (PN_stdfloat)0.5;
480 t = max(t, (PN_stdfloat)0.0);
481 t = min(t, (PN_stdfloat)1.0);
482 LPoint3 inner_point = from_a + t * from_direction;
484 if (collide_cat.is_debug()) {
489 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
491 LVector3 normal = inner_point - get_center();
493 new_entry->set_surface_point(get_center() + normal * get_radius());
494 new_entry->set_interior_point(inner_point - normal * from_radius);
499 new_entry->set_surface_normal(normal);
509test_intersection_from_parabola(
const CollisionEntry &entry)
const {
510 const CollisionParabola *parabola;
511 DCAST_INTO_R(parabola, entry.
get_from(),
nullptr);
514 const LMatrix4 &wrt_mat = wrt_space->get_mat();
518 local_p.xform(wrt_mat);
521 if (!intersects_parabola(t, local_p, parabola->
get_t1(), parabola->
get_t2(),
522 local_p.calc_point(parabola->
get_t1()),
523 local_p.calc_point(parabola->
get_t2()))) {
528 if (collide_cat.is_debug()) {
533 PT(CollisionEntry) new_entry =
new CollisionEntry(entry);
535 LPoint3 into_intersection_point = local_p.calc_point(t);
536 new_entry->set_surface_point(into_intersection_point);
541 LVector3 normal = into_intersection_point - get_center();
543 new_entry->set_surface_normal(normal);
553void CollisionSphere::
555 if (collide_cat.is_debug()) {
557 <<
"Recomputing viz for " << *
this <<
"\n";
560 static const int num_slices = 16;
561 static const int num_stacks = 8;
563 PT(GeomVertexData) vdata =
new GeomVertexData
566 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
568 PT(GeomTristrips) strip =
new GeomTristrips(Geom::UH_static);
569 for (
int sl = 0; sl < num_slices; ++sl) {
570 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
571 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
572 vertex.add_data3(compute_point(0.0, longitude0));
573 for (
int st = 1; st < num_stacks; ++st) {
574 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
575 vertex.add_data3(compute_point(latitude, longitude0));
576 vertex.add_data3(compute_point(latitude, longitude1));
578 vertex.add_data3(compute_point(1.0, longitude0));
580 strip->add_next_vertices(num_stacks * 2);
581 strip->close_primitive();
584 PT(Geom) geom =
new Geom(vdata);
585 geom->add_primitive(strip);
587 _viz_geom->add_geom(geom, get_solid_viz_state());
588 _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
599bool CollisionSphere::
600intersects_line(
double &t1,
double &t2,
601 const LPoint3 &from,
const LVector3 &delta,
602 PN_stdfloat inflate_radius)
const {
628 double A = dot(delta, delta);
630 LVector3 fc = from - get_center();
631 double fc_d2 = dot(fc, fc);
632 double radius = get_radius() + inflate_radius;
633 double C = fc_d2 - radius * radius;
643 double B = 2.0f * dot(delta, fc);
644 double radical = B*B - 4.0*A*C;
646 if (IS_NEARLY_ZERO(radical)) {
648 t1 = t2 = -B /(2.0*A);
651 }
else if (radical < 0.0) {
656 double reciprocal_2A = 1.0/(2.0*A);
657 double sqrt_radical = sqrtf(radical);
658 t1 = ( -B - sqrt_radical ) * reciprocal_2A;
659 t2 = ( -B + sqrt_radical ) * reciprocal_2A;
672bool CollisionSphere::
673intersects_parabola(
double &t,
const LParabola ¶bola,
674 double t1,
double t2,
675 const LPoint3 &p1,
const LPoint3 &p2)
const {
678 if ((p1 - _center).length_squared() > _radius * _radius) {
696 double tmid = (t1 + t2) * 0.5;
697 if (tmid != t1 && tmid != t2) {
698 LPoint3 pmid = parabola.calc_point(tmid);
699 LPoint3 pmid2 = (p1 + p2) * 0.5f;
701 if ((pmid - pmid2).length_squared() > 0.001f) {
703 if (intersects_parabola(t, parabola, t1, tmid, p1, pmid)) {
706 return intersects_parabola(t, parabola, tmid, t2, pmid, p2);
712 if (!intersects_line(t1a, t2a, p1, p2 - p1, 0.0f)) {
716 if (t2a < 0.0 || t1a > 1.0) {
729LVertex CollisionSphere::
730compute_point(PN_stdfloat latitude, PN_stdfloat longitude)
const {
732 csincos(latitude * MathNumbers::pi, &s1, &c1);
735 csincos(longitude * 2.0f * MathNumbers::pi, &s2, &c2);
737 LVertex p(s1 * c2, s1 * s2, c1);
738 return p * get_radius() + get_center();
756 _center.write_datagram(me);
770 me->fillin(scan, manager);
779void CollisionSphere::
781 CollisionSolid::fillin(scan, manager);
782 _center.read_datagram(scan);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Defines a single collision event.
get_into
Returns the CollisionSolid pointer for the particular solid was collided into.
get_from_node_path
Returns the NodePath that represents the CollisionNode that contains the CollisionSolid that triggere...
get_into_node_path
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
get_t1
Returns the starting point on the parabola.
get_t2
Returns the ending point on the parabola.
get_parabola
Returns the parabola specified by this solid.
The abstract base class for all things that can collide with other things in the world,...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
bool has_effective_normal() const
Returns true if a special normal was set by set_effective_normal(), false otherwise.
const LVector3 & get_effective_normal() const
Returns the normal that was set by set_effective_normal().
get_respect_effective_normal
See set_respect_effective_normal().
A spherical collision volume or object.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
static void register_with_read_factory()
Factory method to generate a CollisionSphere object.
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
A class to retrieve the individual data elements previously stored in a Datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
A lightweight class that represents a single element that may be timed and/or counted via stats.
TypeHandle is the identifier used to differentiate C++ class types.
Base class for objects that can be written to and read from Bam files.
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.
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.