Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

octree.cpp

Go to the documentation of this file.
00001 /*
00002     toxic - A Global Illumination Renderer
00003     Copyright (C) 2003-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of toxic.
00007 
00008     toxic is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     toxic is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with toxic; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 #include "octree.h" // include first
00024 #include "common/math/real.h"
00025 #include "common/math/vector3.h"
00026 #include "common/math/vector4.h"
00027 #include "context.h"
00028 #include "ray.h"
00029 
00030 #include <cassert>
00031 #include <limits>
00032 
00033 using namespace sheep;
00034 using namespace std;
00035 using namespace toxic;
00036 
00037 toxic::Octree::Octree(const Matrix4 &m,
00038                       int pop_threshold /*= DEFAULT_OCTREE_POP_THRESHOLD*/,
00039                       int max_subdiv /*= DEFAULT_OCTREE_MAX_SUBDIV*/,
00040                       IntersectionMask intersection_mask /*= INTERSECT_ALL_RAYS*/) :
00041     IBoundedObject(m, 0, intersection_mask),
00042     m_object_count(0),
00043     m_pop_threshold(pop_threshold),
00044     m_max_subdiv(max_subdiv),
00045     m_octree(0)
00046 {
00047 }
00048 
00049 toxic::Octree::~Octree() {
00050     for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00051         delete *i;
00052     }
00053 
00054     delete m_octree;
00055 }
00056 
00057 void toxic::Octree::Insert(IBoundedObject *object) {
00058     assert(object);
00059     m_objects.push_back(object);
00060 }
00061 
00062 void toxic::Octree::Finalize(const Context &context) {
00063     m_object_count = 0;
00064 
00065     for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00066         IObject *child = *i;
00067 
00068         child->Finalize(context);
00069 
00070         m_object_count += child->GetObjectCount();
00071     }
00072 
00073     // Minimum number of objects to use an octree.
00074     const int OBJECTS_THRESHOLD = 8;
00075 
00076     if(m_objects.size() >= OBJECTS_THRESHOLD) {
00077         m_octree = new octree();
00078 
00079         for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00080             m_octree->Insert(*i, (*i)->GetAABB());
00081         }
00082 
00083         object_voxel_intersector ovi;
00084         m_octree->Subdivide(m_pop_threshold, m_max_subdiv, ovi);
00085 
00086         //!\todo This is probably incorrect...
00087         m_aabb = m_octree->GetAABB().Transform(m_m);
00088     } else {
00089         assert(m_octree == 0);
00090 
00091         // Compute AABB from objects.
00092         m_aabb.Invalidate();
00093         for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00094             m_aabb.Include((*i)->GetAABB());
00095         }
00096     }
00097 
00098     // It is not necessary to widen the box of an octree.
00099 }
00100 
00101 Real toxic::Octree::ComputeSurfaceArea() const {
00102     //!\todo Implement.
00103     assert(!"Not implemented yet.");
00104     return 0.0;
00105 }
00106 
00107 void toxic::Octree::EvaluateSurface(const Point2 &input,
00108                                     Point3 *point,
00109                                     Vector3 *geometric_normal) const
00110 {
00111     assert(point);
00112     assert(geometric_normal);
00113 
00114     //!\todo Implement.
00115     assert(!"Not implemented yet.");
00116 }
00117 
00118 bool toxic::Octree::Intersect(const Context &context,
00119                               const Ray &ray,   //!< 'ray' is expressed in world space.
00120                               Hit *hit /*= 0*/) const
00121 {
00122     // Test whether this object intersects with this type of ray.
00123     if(!(m_intersection_mask & ray.GetType()))
00124         return false;
00125 
00126     //!\todo Handle octree transformation.
00127 
00128     if(m_octree) {
00129         if(hit) {
00130             octree_full_visitor visitor(context, ray);
00131 
00132             assert(m_octree);
00133             m_octree->Trace(ray.m_origin, ray.m_direction, visitor);
00134 
00135             if(visitor.m_nearest.m_abscissa < std::numeric_limits<Real>::max()) {
00136                 *hit = visitor.m_nearest;
00137                 return true;
00138             } else return false;
00139         } else {
00140             octree_test_visitor visitor(context, ray);
00141 
00142             assert(m_octree);
00143             m_octree->Trace(ray.m_origin, ray.m_direction, visitor);
00144 
00145             return visitor.m_found;
00146         }
00147     } else {
00148         if(hit) {
00149             Hit nearest;
00150 
00151             nearest.m_abscissa = std::numeric_limits<Real>::max();
00152 
00153             for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00154                 const IBoundedObject *object = *i;
00155                 Hit h;
00156 
00157                 if(object->Intersect(context, ray, &h)) {
00158                     if(h.m_abscissa < nearest.m_abscissa)
00159                         nearest = h;
00160                 }
00161             }
00162 
00163             if(nearest.m_abscissa < std::numeric_limits<Real>::max()) {
00164                 *hit = nearest;
00165                 return true;
00166             } else return false;
00167         } else {
00168             for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00169                 const IBoundedObject *object = *i;
00170 
00171                 if(object->Intersect(context, ray))
00172                     return true;
00173             }
00174 
00175             return false;
00176         }
00177     }
00178 }
00179 
00180 void toxic::Octree::Annotate(const Context &context,
00181                              const ICamera *camera,
00182                              Framebuffer *framebuffer) const
00183 {
00184     for(object_vector_const_it i = m_objects.begin(), e = m_objects.end(); i != e; ++i) {
00185         (*i)->Annotate(context, camera, framebuffer);
00186     }
00187 }
00188 
00189 inline
00190 bool toxic::Octree::object_voxel_intersector::Intersect(const IBoundedObject *object,
00191                                                         const AABB3 &voxel) const
00192 {
00193     assert(object);
00194     return object->GetAABB().Overlaps(voxel);
00195 }
00196 
00197 inline
00198 toxic::Octree::octree_test_visitor::octree_test_visitor(const Context &context,
00199                                                         const Ray &ray) :
00200     m_context(context),
00201     m_ray(ray),
00202     m_found(false)
00203 {
00204 }
00205 
00206 bool toxic::Octree::octree_test_visitor::Trace(const octree_node *node,
00207                                                Real /*t0*/, Real /*t1*/)
00208 {
00209     assert(node);
00210 
00211     for(octree_node::ItemVectorConstIt i = node->m_items.begin(), e = node->m_items.end(); i != e; ++i) {
00212         if((*i)->Intersect(m_context, m_ray)) {
00213             m_found = true;
00214             return true;    // terminate octree traversal
00215         }
00216     }
00217 
00218     return false;   // continue octree traversal
00219 }
00220 
00221 inline
00222 toxic::Octree::octree_full_visitor::octree_full_visitor(const Context &context,
00223                                                         const Ray &ray) :
00224     m_context(context),
00225     m_ray(ray)
00226 {
00227     m_nearest.m_abscissa = std::numeric_limits<Real>::max();
00228 }
00229 
00230 bool toxic::Octree::octree_full_visitor::Trace(const octree_node *node,
00231                                                Real t0, Real t1)
00232 {
00233     assert(node);
00234 
00235     for(octree_node::ItemVectorConstIt i = node->m_items.begin(), e = node->m_items.end(); i != e; ++i) {
00236         const IBoundedObject *object = *i;
00237 
00238 #ifdef USE_MAILBOXES
00239         if(object->m_mailbox_ray_id != m_ray.GetId()) {
00240 #endif  // USE_MAILBOXES
00241             Hit h;
00242 
00243             if(object->Intersect(m_context, m_ray, &h)) {
00244                 if(h.m_abscissa < m_nearest.m_abscissa)
00245                     m_nearest = h;
00246             }
00247 
00248 #ifdef USE_MAILBOXES
00249             object->m_mailbox_ray_id = m_ray.GetId();
00250         }
00251 #endif  // USE_MAILBOXES
00252     }
00253 
00254     //!\todo Make sure the <= and >= are correct.
00255     if(m_nearest.m_abscissa >= t0 && m_nearest.m_abscissa <= t1)
00256         return true;    // terminate octree traversal
00257     else return false;  // continue octree traversal
00258 }

Generated on Tue May 11 01:31:51 2004 for toxic by doxygen 1.3.6