From ad052fc67fe4e76d2f4a01b2381a738da1708cdb Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 12 Jan 2018 00:07:09 +0200 Subject: [PATCH] SceneNode bounds calculation --- src/geom.cc | 41 ++++++++++++++++++++++++++++++++++++++ src/geom.h | 5 +++++ src/snode.cc | 63 +++++++++++++++++++++++++++++++++++++++++++++------------- src/snode.h | 14 +++++++++---- 4 files changed, 105 insertions(+), 18 deletions(-) diff --git a/src/geom.cc b/src/geom.cc index 890d975..0a82566 100644 --- a/src/geom.cc +++ b/src/geom.cc @@ -188,11 +188,23 @@ Box::Box() { } +Box::Box(const AABox &aabox, const Mat4 &xform) + : xform(xform) +{ + min = aabox.min; + max = aabox.max; +} + Box::Box(const Vec3 &min, const Vec3 &max) : AABox(min, max) { } +Box::Box(const Vec3 &min, const Vec3 &max, const Mat4 &xform) + : AABox(min, max), xform(xform) +{ +} + // XXX all this shit is completely untested Box::Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk) { @@ -531,6 +543,35 @@ bool calc_bounding_aabox(AABox *box, const Vec3 *v, int num, const Mat4 &xform) return true; } +bool calc_bounding_box(Box *box, const GeomObject *obj) +{ + switch(obj->type) { + case GOBJ_BOX: + *box = *(Box*)obj; + break; + + case GOBJ_AABOX: + box->min = BOX(obj)->min; + box->max = BOX(obj)->max; + box->xform = Mat4::identity; + break; + + case GOBJ_SPHERE: + { + float r = SPHERE(obj)->radius; + box->min = SPHERE(obj)->center - Vec3(r, r, r); + box->max = SPHERE(obj)->center + Vec3(r, r, r); + box->xform = Mat4::identity; + } + break; + + case GOBJ_PLANE: + default: + return false; + } + return true; +} + bool intersect_sphere_sphere(Disc *result, const Sphere &a, const Sphere &b) { Vec3 dir = b.center - a.center; diff --git a/src/geom.h b/src/geom.h index 24a0b86..f28f878 100644 --- a/src/geom.h +++ b/src/geom.h @@ -76,7 +76,9 @@ public: Mat4 xform; Box(); + Box(const AABox &aabox, const Mat4 &xform); Box(const Vec3 &min, const Vec3 &max); + Box(const Vec3 &min, const Vec3 &max, const Mat4 &xform); Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk); Box(const Vec3 *varr, int vcount); @@ -143,6 +145,9 @@ bool calc_bounding_aabox(AABox *box, const GeomObject **objv, int num); //! calculate the bounding axis-aligned box of multiple points, optionally transformed by `xform` bool calc_bounding_aabox(AABox *box, const Vec3 *v, int num, const Mat4 &xform = Mat4::identity); +//! calculate the bounding box of any object +bool calc_bounding_box(Box *box, const GeomObject *obj); + //! calculate the intersection plane of two spheres. false if there is no plane or infinite planes. bool intersect_sphere_sphere(Plane *result, const Sphere &a, const Sphere &b); //! calculate the intersection line of two planes. returns false if planes are exactly parallel. diff --git a/src/snode.cc b/src/snode.cc index bce8c0a..eee5fce 100644 --- a/src/snode.cc +++ b/src/snode.cc @@ -11,7 +11,7 @@ SceneNode::SceneNode() scene = 0; parent = 0; name = 0; - bvol_valid = false; + local_bvol_valid = false; } SceneNode::SceneNode(Object *obj) @@ -20,7 +20,7 @@ SceneNode::SceneNode(Object *obj) scene = 0; parent = 0; name = 0; - bvol_valid = false; + local_bvol_valid = false; add_object(obj); } @@ -55,8 +55,6 @@ void SceneNode::add_child(SceneNode *node) children.push_back(node); node->parent = this; node->scene = scene; - - bvol_valid = false; } bool SceneNode::remove_child(SceneNode *node) @@ -69,8 +67,6 @@ bool SceneNode::remove_child(SceneNode *node) node->parent = 0; node->scene = 0; children.erase(it); - - bvol_valid = false; return true; } return false; @@ -102,7 +98,7 @@ void SceneNode::add_object(Object *obj) this->obj.push_back(obj); obj->node = this; - bvol_valid = false; + local_bvol_valid = false; } bool SceneNode::remove_object(Object *o) @@ -118,7 +114,7 @@ bool SceneNode::remove_object(Object *o) } obj.erase(it); - bvol_valid = false; + local_bvol_valid = false; return true; } @@ -287,15 +283,54 @@ bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const return false; } -const Box &SceneNode::calc_bounds() +const AABox &SceneNode::calc_local_bounds() +{ + local_bvol = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); + + // calculate the axis-aligned bounding box of all objects in this node + int nobj = obj.size(); + for(int i=0; iget_aabox(); + calc_bounding_aabox(&local_bvol, &local_bvol, &tmp); + } + + local_bvol_valid = true; + return local_bvol; +} + +const AABox &SceneNode::get_local_bounds() const { - // TODO + if(!local_bvol_valid) { + ((SceneNode*)this)->calc_local_bounds(); + } + return local_bvol; +} + +AABox SceneNode::get_node_bounds() const +{ + get_local_bounds(); // validate local_bvol + + // calculate the transformed local_bvol + Box node_bbox = Box(local_bvol, xform); + + // then calculate the axis-aligned bounding box + AABox aabox; + calc_bounding_aabox(&aabox, &node_bbox); + return aabox; } -const Box &SceneNode::get_bounds() const +AABox SceneNode::get_bounds() const { - if(!bvol_valid) { - return ((SceneNode*)this)->calc_bounds(); + AABox sub_aabb = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); + + // calculate the bounding box of all children + int nchild = children.size(); + for(int i=0; iget_bounds(); + calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp); } - return bvol; + + AABox aabb; + calc_bounding_aabox(&aabb, &local_bvol, &sub_aabb); + return aabb; } diff --git a/src/snode.h b/src/snode.h index b88c1ae..94ccb6a 100644 --- a/src/snode.h +++ b/src/snode.h @@ -24,8 +24,8 @@ private: Mat4 xform; Mat4 inv_xform; - mutable bool bvol_valid; - mutable Box bvol; + mutable bool local_bvol_valid; + mutable AABox local_bvol; public: Scene *scene; // scene to which this node belongs @@ -74,8 +74,14 @@ public: bool intersect(const Ray &ray, HitPoint *hit) const; - const Box &calc_bounds(); - const Box &get_bounds() const; + // cached local bounding box (all objects in this node in model space) + const AABox &calc_local_bounds(); + const AABox &get_local_bounds() const; + + // world bounding box of the node + AABox get_node_bounds() const; + // world bounding box of the node and it's subtree + AABox get_bounds() const; }; #endif // SNODE_H_ -- 1.7.10.4