1 #ifndef AABB_HXX
  2 #define AABB_HXX
  3 
  4 #include "Primitive.hxx"
  5 
  6 class AABB : public Primitive
  7 {
  8     Vec3f _center;
  9     Vec3f _min;
 10     Vec3f _max;
 11     
 12     /**
 13      * compute bounding box for an axis aligned box
 14      * with the help of min and max vector
 15      */
 16     Box CalcBounds()
 17     {
 18         Box bb;
 19         bb.Extend(_min);
 20         bb.Extend(_max);    
 21         return bb;
 22     }
 23 
 24 public:
 25     AABB(Vec3f min, Vec3f max) : _min(min), _max(max)
 26     {
 27         // compute center of the axis aligned bounding box
 28         _center = (_min + _max) * 0.5;
 29     };
 30 
 31     ~AABB()
 32     {};
 33 
 34     bool Intersect(Ray &ray)
 35     {
 36         float tmin, tmax, tymin, tymax, tzmin, tzmax;
 37 
 38         // inverse direction to catch float problems
 39         Vec3f invrd = 1.0 / ray.dir;
 40 
 41         if (invrd.x() >= 0)
 42         {
 43             tmin = (_min.x() - ray.org.x()) * invrd.x();
 44             tmax = (_max.x() - ray.org.x()) * invrd.x();
 45         } else
 46         {
 47             tmin = (_max.x() - ray.org.x()) * invrd.x();
 48             tmax = (_min.x() - ray.org.x()) * invrd.x();
 49         }
 50 
 51         if (invrd.y() >= 0)
 52         {
 53             tymin = (_min.y() - ray.org.y()) * invrd.y();
 54             tymax = (_max.y() - ray.org.y()) * invrd.y();
 55         } else
 56         {
 57             tymin = (_max.y() - ray.org.y()) * invrd.y();
 58             tymax = (_min.y() - ray.org.y()) * invrd.y();
 59         }
 60 
 61         if ( (tmin > tymax) || (tymin > tmax) ) return false;
 62         if ( tymin > tmin) tmin = tymin;
 63         if ( tymax < tmax) tmax = tymax;
 64     
 65         if (invrd.z() >= 0)
 66         {
 67             tzmin = (_min.z() - ray.org.z()) * invrd.z();
 68             tzmax = (_max.z() - ray.org.z()) * invrd.z();
 69         }else
 70         {
 71             tzmin = (_max.z() - ray.org.z()) * invrd.z();
 72             tzmax = (_min.z() - ray.org.z()) * invrd.z();
 73         }
 74 
 75         if ( (tmin > tzmax) || (tzmin > tmax) ) return false;
 76         if ( tzmin > tmin) tmin = tzmin;
 77         if ( tzmax < tmax) tmax = tzmax;
 78 
 79         // check if values are valid
 80         if (tmin < 0) tmin = tmax;
 81         if (tmax < 0) return false;
 82 
 83         ray.t = tmin;
 84         ray.hit = this;
 85         return true;
 86     };
 87     
 88     /**
 89      * compute normal of an axis aligned box
 90      * Therefore take the maximum entry of dir (the vector from the center of the box to the hitpoint),
 91      * which indicates on which side the box is hit. The normal is then of one of the unit vector.
 92      * Important: take the side length into account.
 93      */
 94     virtual Vec3f GetNormal(Ray &ray)
 95     {   
 96         Vec3f hit = ray.org + ray.t * ray.dir;
 97         Vec3f dir = hit - _center;
 98         
 99         Vec3f width = fabs(_max - _min);
100         Vec3f ratio = fabs( Vec3f(  dir[0] / width[0], 
101                                     dir[1] / width[1], 
102                                     dir[2] / width[2] ));
103         int max = ratio.MaxDim();
104         
105         Vec3f normal = Vec3f(0);
106         
107         if (dir[max] > 0)
108                 normal[max] =  1.0;
109         else    normal[max] = -1.0;
110 
111         return normal;
112     };
113     
114     /** 
115      * compute UV values for a box
116      */
117     virtual Vec2f GetUV(Ray &ray) 
118     {   
119         /**
120          * first get the normal vector
121          */
122         Vec3f normal = (*this).GetNormal(ray);
123         
124         /**
125          * and check which side of the box is hit
126          * save the corresponding axis in get_i (0 = xAxis, 1 = yAxis, 2 = zAxis)
127          */     
128         int get_i = 0;
129         for (unsigned int i = 0; i < 3; i++)
130             if ( fabs(normal[i]) )
131                 get_i = i;
132 
133         /** 
134          * then take the vector from the hitpoint to
135          * either the min or the max vector of the box
136          */
137         Vec3f hitpoint = ray.org + ray.t * ray.dir;
138         Vec3f diff;
139                 
140         if ( normal[get_i] == 1)
141                 diff = hitpoint - _min;
142         else    diff = hitpoint - _max;
143         
144         /** 
145          * normalize this vector, to get entries in between 0 and 1
146          */
147         Normalize(diff);
148         
149         /**
150          * take two entries out of the vector
151          * depending on the side which is hit
152          */
153         float u = diff[ (get_i + 2) % 3 ];
154         float v = diff[ (get_i + 1) % 3 ];
155                                     
156         return Vec2f(u,v);
157     };
158   
159 };
160 
161 #endif


syntax highlighted by Code2HTML, v. 0.9.1