Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r955 - trunk/Model/Groups


Chronological Thread 
  • From: boulos@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r955 - trunk/Model/Groups
  • Date: Fri, 24 Feb 2006 00:03:17 -0700 (MST)

Author: boulos
Date: Fri Feb 24 00:03:16 2006
New Revision: 955

Added:
   trunk/Model/Groups/DynBVH.cc
   trunk/Model/Groups/DynBVH.h
Modified:
   trunk/Model/Groups/CMakeLists.txt
   trunk/Model/Groups/Group.cc
   trunk/Model/Groups/Group.h
Log:
Adding const version of get and changing 
getSize to be const. 

Adding the first compiling version of the 
SIGGRAPH Dynamic BVH (not yet tested and lacks
interval arithmetic culling).



Modified: trunk/Model/Groups/CMakeLists.txt
==============================================================================
--- trunk/Model/Groups/CMakeLists.txt   (original)
+++ trunk/Model/Groups/CMakeLists.txt   Fri Feb 24 00:03:16 2006
@@ -10,6 +10,8 @@
 SET (Manta_Groups_SRCS
      Groups/BVH.cc
      Groups/BVH.h
+     Groups/DynBVH.h
+     Groups/DynBVH.cc
      Groups/GriddedGroup.cc
      Groups/GriddedGroup.h
      Groups/Group.cc

Added: trunk/Model/Groups/DynBVH.cc
==============================================================================
--- (empty file)
+++ trunk/Model/Groups/DynBVH.cc        Fri Feb 24 00:03:16 2006
@@ -0,0 +1,373 @@
+#include <Model/Groups/DynBVH.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+using namespace Manta;
+
+const float BVH_C_isec = 10.f;
+const float BVH_C_trav = 10.f;
+
+void DynBVH::intersect(const RenderContext& context, RayPacket& rays) const
+{
+    rays.computeInverseDirections();
+    rays.computeSigns();
+
+    intersectNode(0,context,rays);
+}
+
+void DynBVH::intersectNode(int nodeID, const RenderContext& context, 
RayPacket& rays) const
+{
+    const BVHNode& node = nodes[nodeID];
+    int firstActive = firstIntersects(node.bounds, rays);
+
+    if (firstActive != rays.end())
+    {
+        if (node.isLeaf())
+        {
+            // we already know that one of the rays from begin to end
+            // hits the object, so lastActive is going to find something
+            // we need not create a subpacket to help it stop early
+
+            // actually if we're just one ray it'll look more than it
+            // needs to... damn
+            int lastActive = lastIntersects(node.bounds, rays);
+
+            // build a subpacket from firstActive to lastActive
+            RayPacket subpacket(rays, firstActive, lastActive);
+
+            for (int i = 0; i < node.children; i++ )
+            {
+                const int object_id = object_ids[node.child+i];
+                this->get(object_id)->intersect(context,subpacket);
+            }
+        }
+        else
+        {
+            // make a subpacket from the (possibly) new firstActive to the 
current end
+            RayPacket subpacket(rays, firstActive, rays.end());
+
+            // recurse
+            intersectNode(node.child+0, context, subpacket);
+            intersectNode(node.child+1, context, subpacket);
+        }
+    }
+}
+
+// return the first index (between [rays.begin(),rays.end()]) which hits the 
box
+int DynBVH::firstIntersects(const BBox& box, const RayPacket& rays) const
+{
+    for (int ray = rays.begin(); ray < rays.end(); ray++ )
+    {
+        float maximum_minimum = 1e-4;
+        float minimum_maximum = rays.getMinT(ray);
+
+        float x_minimum = (box[rays.getSign(ray,0)][0]   - 
rays.getOrigin(ray,0)) * rays.getInverseDirection(ray,0);
+        float x_maximum = (box[1-rays.getSign(ray,0)][0] - 
rays.getOrigin(ray,0)) * rays.getInverseDirection(ray,0);
+
+        float y_minimum = (box[rays.getSign(ray,1)][1]   - 
rays.getOrigin(ray,1)) * rays.getInverseDirection(ray,1);
+        float y_maximum = (box[1-rays.getSign(ray,1)][1] - 
rays.getOrigin(ray,1)) * rays.getInverseDirection(ray,1);
+
+        float z_minimum = (box[rays.getSign(ray,2)][2]   - 
rays.getOrigin(ray,2)) * rays.getInverseDirection(ray,2);
+        float z_maximum = (box[1-rays.getSign(ray,2)][2] - 
rays.getOrigin(ray,2)) * rays.getInverseDirection(ray,2);
+
+        if ( minimum_maximum < x_minimum ||
+             maximum_minimum > x_maximum )
+            continue;
+        if ( minimum_maximum > x_maximum )
+            minimum_maximum = x_maximum;
+        if ( maximum_minimum < x_minimum )
+            maximum_minimum = x_minimum;
+        if ( minimum_maximum < y_minimum ||
+             maximum_minimum > y_maximum )
+            continue;
+        if ( minimum_maximum > y_maximum )
+                minimum_maximum = y_maximum;
+        if ( maximum_minimum < y_minimum )
+            maximum_minimum = y_minimum;
+
+        if ( minimum_maximum >= z_minimum &&
+             maximum_minimum <= z_maximum )
+            return ray; // found a hit
+    }
+    return rays.end();
+}
+
+// return the last index which hits the box
+int DynBVH::lastIntersects(const BBox& box, const RayPacket& rays) const
+{
+    for (int ray = rays.end() - 1; ray >= rays.begin(); ray-- )
+    {
+        float maximum_minimum = 1e-4;
+        float minimum_maximum = rays.getMinT(ray);
+
+        float x_minimum = (box[rays.getSign(ray,0)][0]   - 
rays.getOrigin(ray,0)) * rays.getInverseDirection(ray,0);
+        float x_maximum = (box[1-rays.getSign(ray,0)][0] - 
rays.getOrigin(ray,0)) * rays.getInverseDirection(ray,0);
+
+        float y_minimum = (box[rays.getSign(ray,1)][1]   - 
rays.getOrigin(ray,1)) * rays.getInverseDirection(ray,1);
+        float y_maximum = (box[1-rays.getSign(ray,1)][1] - 
rays.getOrigin(ray,1)) * rays.getInverseDirection(ray,1);
+
+        float z_minimum = (box[rays.getSign(ray,2)][2]   - 
rays.getOrigin(ray,2)) * rays.getInverseDirection(ray,2);
+        float z_maximum = (box[1-rays.getSign(ray,2)][2] - 
rays.getOrigin(ray,2)) * rays.getInverseDirection(ray,2);
+
+        if ( minimum_maximum < x_minimum ||
+             maximum_minimum > x_maximum )
+            continue;
+        if ( minimum_maximum > x_maximum )
+            minimum_maximum = x_maximum;
+        if ( maximum_minimum < x_minimum )
+            maximum_minimum = x_minimum;
+        if ( minimum_maximum < y_minimum ||
+             maximum_minimum > y_maximum )
+            continue;
+        if ( minimum_maximum > y_maximum )
+                minimum_maximum = y_maximum;
+        if ( maximum_minimum < y_minimum )
+            maximum_minimum = y_minimum;
+
+        if ( minimum_maximum >= z_minimum &&
+             maximum_minimum <= z_maximum )
+            return ray; // found a hit
+    }
+    return rays.begin();
+}
+
+void DynBVH::preprocess(const PreprocessContext& context)
+{
+    Group::preprocess(context);
+
+    nodes = new BVHNode[2*this->getSize()];
+    object_ids = new int[this->getSize()];
+    for ( int i = 0; i < this->getSize(); i++ )
+        object_ids[i] = i;
+
+    num_nodes = 1; // root node
+    build(context, 0, 0, this->getSize(), num_nodes);
+    updateBounds(context, 0);
+}
+
+void DynBVH::build(const PreprocessContext& context,
+                   int nodeID, int objectBegin, int objectEnd,
+                   int& nextFree, int depth)
+{
+
+    if (objectBegin <= objectEnd)
+    {
+        printf("ERROR! Tried building BVH over 
%d,%d\n",objectBegin,objectEnd);
+        exit(-1);
+    }
+
+    BVHNode& node = nodes[nodeID];
+
+    int bestAxis = -1;
+    int split = partitionSAH(context, objectBegin,objectEnd,bestAxis);
+
+    if (bestAxis == -1)
+    {
+        // make leaf
+        node.makeLeaf(objectBegin, objectEnd-objectBegin);
+
+        std::sort(object_ids+objectBegin,object_ids+objectEnd);
+
+        num_nodes++;
+    }
+    else
+    {
+        // make internal node
+        node.makeInternal(nextFree, bestAxis);
+        num_nodes++;
+        // allocate two spots
+        nextFree += 2;
+
+        build(context, node.child+0,objectBegin,split,nextFree,depth+1);
+        build(context, node.child+1, split, objectEnd,nextFree,depth+1);
+    }
+
+    if (depth == 0)
+    {
+        printf("DynBVH Build Complete\n");
+    }
+
+}
+
+void DynBVH::updateBounds(const PreprocessContext& context, int ID)
+{
+    BVHNode& node = nodes[ID];
+    if (node.isLeaf())
+    {
+        node.bounds.reset();
+        for (int i = 0; i < node.children; i++ )
+        {
+            BBox temp;
+            int obj_id = object_ids[node.child + i];
+            this->get(obj_id)->computeBounds(context,temp);
+
+            node.bounds.extendByBox(temp);
+        }
+        node.axis = 0;
+        node.axis_sign = 0;
+    }
+    else
+    {
+        int left_son = node.child;
+        int right_son = left_son + 1;
+        updateBounds(context, left_son);
+        updateBounds(context, right_son);
+
+        node.bounds.reset();
+        const BVHNode& left_node = nodes[left_son];
+        const BVHNode& right_node = nodes[right_son];
+
+        node.bounds.extendByBox(left_node.bounds);
+        node.bounds.extendByBox(right_node.bounds);
+    }
+}
+
+int DynBVH::partitionSAH(const PreprocessContext& context,
+                         int objBegin, int objEnd, int& output_axis)
+{
+    int num_objects = objEnd - objBegin;
+    if ( num_objects == 1 )
+    {
+        output_axis = -1;
+        return -1;
+    }
+
+    BVHCostEval best_cost;
+    best_cost.cost = BVH_C_isec * num_objects;
+    best_cost.axis = -1;
+
+    for ( int axis = 0; axis < 3; axis++ )
+    {
+        BVHCostEval new_cost;
+        if ( buildEvents(context, objBegin,objEnd,axis,new_cost) )
+        {
+            if ( new_cost.cost < best_cost.cost )
+            {
+                best_cost = new_cost;
+            }
+        }
+    }
+
+    output_axis = best_cost.axis;
+    if ( output_axis != -1 )
+    {
+        // build the events and sort them
+        std::vector<BVHSAHEvent> events;
+        for ( int i = objBegin; i < objEnd; i++ )
+        {
+            BVHSAHEvent new_event;
+            BBox tri_box;
+            this->get(object_ids[i])->computeBounds(context, tri_box);
+            new_event.position = tri_box.center()[output_axis];
+            new_event.obj_id   = object_ids[i];
+            events.push_back(new_event);
+        }
+
+        std::sort(events.begin(), events.end(), CompareBVHSAHEvent());
+
+        for ( int i = objBegin; i < objEnd; i++ )
+        {
+            object_ids[i] = events[i-objBegin].obj_id;
+        }
+
+        int result = objBegin + best_cost.event;
+
+        if ( result == objBegin || result == objEnd )
+        {
+            if ( num_objects < 8 )
+            {
+                output_axis = -1;
+                return 0;
+            }
+            result = objBegin + num_objects/2;
+            return result;
+        }
+        else
+            return result;
+    }
+    else
+    {
+        return 0; // making a leaf anyway
+    }
+
+}
+
+bool DynBVH::buildEvents(const PreprocessContext& context,
+                         int first,
+                         int last,
+                         int axis,
+                         BVHCostEval& best_eval)
+{
+    BBox overall_box;
+    std::vector<BVHSAHEvent> events;
+    for ( int i = first; i < last; i++ )
+    {
+        BVHSAHEvent new_event;
+        BBox tri_box;
+        this->get(object_ids[i])->computeBounds(context, tri_box);
+        new_event.position = tri_box.center()[axis];
+        new_event.obj_id   = object_ids[i];
+        events.push_back(new_event);
+
+        overall_box.extendByBox(tri_box);
+    }
+
+    std::sort(events.begin(),events.end(),CompareBVHSAHEvent());
+
+    int num_events = int(events.size());
+    BBox left_box;
+
+    int num_left = 0;
+    int num_right = num_events;
+
+    for ( size_t i = 0; i < events.size(); i++ )
+    {
+        events[i].num_left = num_left;
+        events[i].num_right = num_right;
+        events[i].left_area = left_box.computeArea();
+
+        BBox tri_box;
+        this->get(events[i].obj_id)->computeBounds(context, tri_box);
+        left_box.extendByBox(tri_box);
+
+        num_left++;
+        num_right--;
+    }
+
+    BBox right_box;
+
+    best_eval.cost = FLT_MAX;
+    best_eval.event = -1;
+
+    for ( int i = num_events - 1; i >= 0; i-- )
+    {
+        BBox tri_box;
+        this->get(events[i].obj_id)->computeBounds(context, tri_box);
+
+        right_box.extendByBox(tri_box);
+
+        if ( events[i].num_left > 0 && events[i].num_right > 0 )
+        {
+            events[i].right_area = right_box.computeArea();
+
+            float this_cost = (events[i].num_left * events[i].left_area +
+                               events[i].num_right * events[i].right_area);
+            this_cost /= overall_box.computeArea();
+            this_cost *= BVH_C_isec;
+            this_cost += BVH_C_trav;
+
+            events[i].cost = this_cost;
+            if ( this_cost < best_eval.cost )
+            {
+                best_eval.cost       = this_cost;
+                best_eval.position   = events[i].position;
+                best_eval.axis       = axis;
+                best_eval.event      = i;
+                best_eval.num_left   = events[i].num_left;
+                best_eval.num_right  = events[i].num_right;
+
+            }
+        }
+    }
+    return best_eval.event != -1;
+}

Added: trunk/Model/Groups/DynBVH.h
==============================================================================
--- (empty file)
+++ trunk/Model/Groups/DynBVH.h Fri Feb 24 00:03:16 2006
@@ -0,0 +1,124 @@
+#ifndef _MANTA_DYNBVH_H_
+#define _MANTA_DYNBVH_H_
+
+#include <Model/Groups/Group.h>
+#include <Core/Geometry/BBox.h>
+#include <Interface/RayPacket.h>
+
+namespace Manta
+{
+    class DynBVH : public Group
+    {
+    public:
+        struct BVHNode
+        {
+            BBox bounds;
+            int child; // my child
+            unsigned char axis; // 0 = x, 1 = y, 2 = z,
+            unsigned char axis_sign; // 0 means left-right, 1 means 
right-left
+            short children; // num children
+
+            // 24 bytes + 4 bytes + 1 + 1 + 2 = 32 bytes
+
+            inline void makeLeaf(int first_child, short num_children)
+            {
+                child = first_child;
+                children = num_children;
+                axis = 0;
+                axis_sign = 0;
+            }
+
+            inline void makeInternal(int first_child, unsigned char _axis)
+            {
+                child = first_child;
+                children = 0;
+                axis = _axis;
+                axis_sign = 0; // for now
+            }
+
+            inline bool isLeaf() const
+            {
+                return children != 0;
+            }
+
+        };
+
+        BVHNode* nodes;
+        int* object_ids;
+        int num_nodes;
+
+        DynBVH() : nodes(NULL), num_nodes(0)
+        {}
+
+        void preprocess(const PreprocessContext&);
+        void intersect(const RenderContext& context, RayPacket& rays) const;
+        void intersectNode(int nodeID, const RenderContext& context, 
RayPacket& rays) const;
+
+
+        // return the first index (between [rays.begin(),rays.end()]) which 
hits the box
+        int firstIntersects(const BBox& box, const RayPacket& rays) const;
+        // return the last index which hits the box
+        int lastIntersects(const BBox& box, const RayPacket& rays) const;
+
+        void computeBounds(const PreprocessContext&,
+                           BBox& bbox) const
+        {
+            if (num_nodes)
+                bbox = nodes[0].bounds;
+        }
+
+        static Group* create(const vector<string>&)
+        {
+            return new DynBVH();
+        }
+
+        void build(const PreprocessContext& context,
+                   int nodeID, int objectBegin, int objectEnd,
+                   int &nextFree, int depth = 0);
+
+        void updateBounds(const PreprocessContext& context, int ID = 0);
+
+
+        int partitionSAH(const PreprocessContext& context,
+                         int objBegin, int objEnd, int& output_axis);
+
+        struct BVHCostEval
+        {
+            float position;
+            float cost;
+            int num_left;
+            int num_right;
+            int event;
+            int axis;
+        };
+
+        struct BVHSAHEvent
+        {
+            float position;
+            int obj_id;
+            float left_area;
+            float right_area;
+            int num_left;
+            int num_right;
+            float cost;
+        };
+
+        struct CompareBVHSAHEvent
+        {
+            bool operator()(const BVHSAHEvent& x, const BVHSAHEvent& y)
+            {
+                // add obj_id sorting in here automatically?
+                return x.position < y.position;
+            }
+        };
+
+        bool buildEvents(const PreprocessContext& context,
+                         int first,
+                         int last,
+                         int axis,
+                         BVHCostEval& eval);
+
+    };
+};
+
+#endif

Modified: trunk/Model/Groups/Group.cc
==============================================================================
--- trunk/Model/Groups/Group.cc (original)
+++ trunk/Model/Groups/Group.cc Fri Feb 24 00:03:16 2006
@@ -36,7 +36,12 @@
   return objs[i];
 }
 
-void Group::shrinkTo(int firstNumObjs, bool deleteRemainder) 
+const Object* Group::get(int i) const
+{
+    return objs[i];
+}
+
+void Group::shrinkTo(int firstNumObjs, bool deleteRemainder)
 {
     if (deleteRemainder)
         for(int i=firstNumObjs;i<static_cast<int>(objs.size());i++)
@@ -44,7 +49,7 @@
     objs.resize(firstNumObjs);
 }
 
-int Group::getSize() 
+int Group::getSize() const
 {
   return static_cast<int>(objs.size());
 }

Modified: trunk/Model/Groups/Group.h
==============================================================================
--- trunk/Model/Groups/Group.h  (original)
+++ trunk/Model/Groups/Group.h  Fri Feb 24 00:03:16 2006
@@ -19,9 +19,10 @@
     void add(Object* obj);
     void set( int i, Object *obj );
     Object *get( int i );
+    const Object* get(int i) const;
 
     void shrinkTo(int firstNumObjs, bool deleteRemainder);
-    int getSize();
+    int getSize() const;
 
     virtual void preprocess(const PreprocessContext&);
     virtual void intersect(const RenderContext& context, RayPacket& rays) 
const;




  • [MANTA] r955 - trunk/Model/Groups, boulos, 02/24/2006

Archive powered by MHonArc 2.6.16.

Top of page