00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "octree.h"
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 ,
00039 int max_subdiv ,
00040 IntersectionMask intersection_mask ) :
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
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
00087 m_aabb = m_octree->GetAABB().Transform(m_m);
00088 } else {
00089 assert(m_octree == 0);
00090
00091
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
00099 }
00100
00101 Real toxic::Octree::ComputeSurfaceArea() const {
00102
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
00115 assert(!"Not implemented yet.");
00116 }
00117
00118 bool toxic::Octree::Intersect(const Context &context,
00119 const Ray &ray,
00120 Hit *hit ) const
00121 {
00122
00123 if(!(m_intersection_mask & ray.GetType()))
00124 return false;
00125
00126
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 , Real )
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;
00215 }
00216 }
00217
00218 return false;
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
00255 if(m_nearest.m_abscissa >= t0 && m_nearest.m_abscissa <= t1)
00256 return true;
00257 else return false;
00258 }