SceneNode bounds calculation
authorJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 11 Jan 2018 22:07:09 +0000 (00:07 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Thu, 11 Jan 2018 22:07:09 +0000 (00:07 +0200)
src/geom.cc
src/geom.h
src/snode.cc
src/snode.h

index 890d975..0a82566 100644 (file)
@@ -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;
index 24a0b86..f28f878 100644 (file)
@@ -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.
index bce8c0a..eee5fce 100644 (file)
@@ -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; i<nobj; i++) {
+               AABox tmp = obj[i]->get_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; i<nchild; i++) {
+               AABox tmp = children[i]->get_bounds();
+               calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
        }
-       return bvol;
+
+       AABox aabb;
+       calc_bounding_aabox(&aabb, &local_bvol, &sub_aabb);
+       return aabb;
 }
index b88c1ae..94ccb6a 100644 (file)
@@ -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_