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

ring.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 "ring.h"   // include first
00024 #include "context.h"
00025 #include "hit.h"
00026 #include "isurfaceshader.h"
00027 #include "ray.h"
00028 #include "scene.h"
00029 #include "settings.h"
00030 #include "statistics.h"
00031 #include "surfacebasis.h"
00032 #include "utilities.h"
00033 
00034 #include <algorithm>    // std::min<>(), std::max<>()
00035 #include <cassert>
00036 #include <cmath>
00037 #include <limits>
00038 
00039 using namespace sheep;
00040 using namespace std;
00041 using namespace toxic;
00042 
00043 Ring::Ring(const Matrix4 &m,
00044            const ISurfaceShader *surface_shader,
00045            Real inner_radius,
00046            IntersectionMask intersection_mask /*= INTERSECT_ALL_RAYS*/) :
00047     IAreaLight(m, surface_shader, intersection_mask),
00048     m_inner_radius2(sq(inner_radius)),
00049     m_center(TransformToWorld(Point3(0.0))),
00050     m_ex(TransformToWorld(Vector3(1.0, 0.0, 0.0))),
00051     m_ey(TransformToWorld(Vector3(0.0, 1.0, 0.0))),
00052     m_ez(TransformToWorld(Vector3(0.0, 0.0, 1.0)))
00053 {
00054     assert(inner_radius >= 0.0 && inner_radius < 1.0);
00055 
00056     m_aabb = AABB3(Point3(-1.0, -0.5, -1.0), Point3(1.0, 0.5, 1.0)).Transform(m);
00057 
00058     // Enlarge the object bounding box to avoid numerical instabilities.
00059     m_aabb.Extend(OBJECT_AABB_EXTENSION);
00060 }
00061 
00062 Real Ring::ComputeSurfaceArea() const {
00063     //!\todo Implement.
00064     return 0.0;
00065 }
00066 
00067 void Ring::EvaluateSurface(const Point2 &input,
00068                            Point3 *point,
00069                            Vector3 *geometric_normal) const
00070 {
00071     assert(point);
00072     assert(geometric_normal);
00073 
00074     //!\todo Implement.
00075     assert(!"Not implemented yet.");
00076 }
00077 
00078 bool Ring::Intersect(const Context &context,
00079                      const Ray &ray,    //!< 'ray' is expressed in world space.
00080                      Hit *hit /*= 0*/) const
00081 {
00082     // Test whether this object intersects with this type of ray.
00083     if(!(m_intersection_mask & ray.GetType()))
00084         return false;
00085 
00086     ++context.m_statistics->m_tested_intersections;
00087 
00088     Ray r = TransformToLocal(ray);
00089     const Real inv_scale = 1.0 / r.m_direction.Norm();
00090 
00091     // Normalize the ray's direction vector.
00092     r.m_direction *= inv_scale;
00093 
00094     Real min_t = std::numeric_limits<Real>::max();
00095     Vector3 normal;
00096 
00097     // Test intersection with the outer wrap.
00098 
00099     const Real a = sq(r.m_direction.m_x) + sq(r.m_direction.m_z);
00100     const Real b0 = sq(r.m_origin.m_x) + sq(r.m_origin.m_z) - 1.0;  // outer cylinder has unit radius
00101     const Real c = r.m_direction.m_x * r.m_origin.m_x + r.m_direction.m_z * r.m_origin.m_z;
00102 
00103     const Real delta0 = sq(c) - a * b0;
00104 
00105     if(delta0 >= 0.0) {
00106         const Real sqrt_delta0 = sqrt(delta0);
00107         //!\todo Handle the case where a=0.0.
00108         const Real t0 = (-c - sqrt_delta0) / a;
00109         const Real t1 = (-c + sqrt_delta0) / a;
00110 
00111         if(t0 >= 0.0) { // first test, don't compare t0 to min_t (since min_t is almost +infinity)
00112             // The ray intersects the cylinder supporting the outer wrap.
00113 
00114             const Real py = r.m_origin.m_y + t0 * r.m_direction.m_y;
00115 
00116             if(py >= -0.5 && py <= 0.5) {
00117                 min_t = t0; // the ray intersects the outer wrap
00118 
00119                 normal.m_x = r.m_origin.m_x + t0 * r.m_direction.m_x;
00120                 normal.m_y = 0.0;
00121                 normal.m_z = r.m_origin.m_z + t0 * r.m_direction.m_z;
00122             }
00123         }
00124 
00125         if(t1 >= 0.0 && t1 < min_t) {
00126             // The ray intersects the cylinder supporting the outer wrap.
00127 
00128             const Real py = r.m_origin.m_y + t1 * r.m_direction.m_y;
00129 
00130             if(py >= -0.5 && py <= 0.5) {
00131                 min_t = t1; // the ray intersects the outer wrap
00132 
00133                 normal.m_x = r.m_origin.m_x + t1 * r.m_direction.m_x;
00134                 normal.m_y = 0.0;
00135                 normal.m_z = r.m_origin.m_z + t1 * r.m_direction.m_z;
00136             }
00137         }
00138     }
00139 
00140     // Test intersection with the inner wrap.
00141 
00142     const Real b1 = sq(r.m_origin.m_x) + sq(r.m_origin.m_z) - m_inner_radius2;  // inner cylinder has custom radius
00143 
00144     const Real delta1 = sq(c) - a * b1;
00145 
00146     if(delta1 >= 0.0) {
00147         const Real sqrt_delta1 = sqrt(delta1);
00148         //!\todo Handle the case where a=0.0.
00149         const Real t0 = (-c - sqrt_delta1) / a;
00150         const Real t1 = (-c + sqrt_delta1) / a;
00151 
00152         if(t0 >= 0.0 && t0 < min_t) {
00153             // The ray intersects the cylinder supporting the inner wrap.
00154 
00155             const Real py = r.m_origin.m_y + t0 * r.m_direction.m_y;
00156 
00157             if(py >= -0.5 && py <= 0.5) {
00158                 min_t = t0; // the ray intersects the inner wrap
00159 
00160                 normal.m_x = -(r.m_origin.m_x + t0 * r.m_direction.m_x);
00161                 normal.m_y = 0.0;
00162                 normal.m_z = -(r.m_origin.m_z + t0 * r.m_direction.m_z);
00163             }
00164         }
00165 
00166         if(t1 >= 0.0 && t1 < min_t) {
00167             // The ray intersects the cylinder supporting the inner wrap.
00168 
00169             const Real py = r.m_origin.m_y + t1 * r.m_direction.m_y;
00170 
00171             if(py >= -0.5 && py <= 0.5) {
00172                 min_t = t1; // the ray intersects the inner wrap
00173 
00174                 normal.m_x = -(r.m_origin.m_x + t1 * r.m_direction.m_x);
00175                 normal.m_y = 0.0;
00176                 normal.m_z = -(r.m_origin.m_z + t1 * r.m_direction.m_z);
00177             }
00178         }
00179     }
00180 
00181     // Test intersection with the upper cap.
00182 
00183     //!\todo Handle the case where r.m_direction.m_y=0.0.
00184     const Real t0 = (0.5 - r.m_origin.m_y) / r.m_direction.m_y;
00185 
00186     if(t0 >= 0.0 && t0 < min_t) {
00187         // The ray intersects the plane supporting the upper cap.
00188 
00189         const Real px = r.m_origin.m_x + t0 * r.m_direction.m_x;
00190         const Real pz = r.m_origin.m_z + t0 * r.m_direction.m_z;
00191         const Real d2 = sq(px) + sq(pz);    // square of the distance to the Y axis
00192 
00193         if(d2 <= 1.0 && d2 >= m_inner_radius2) {
00194             min_t = t0; // the ray intersects the upper cap
00195 
00196             normal.m_x = normal.m_z = 0.0;
00197             normal.m_y = 1.0;
00198         }
00199     }
00200 
00201     // Test intersection with the lower cap.
00202 
00203     //!\todo Handle the case where r.m_direction.m_y=0.0.
00204     const Real t1 = (-0.5 - r.m_origin.m_y) / r.m_direction.m_y;
00205 
00206     if(t1 >= 0.0 && t1 < min_t) {
00207         // The ray intersects the plane supporting the lower cap.
00208 
00209         const Real px = r.m_origin.m_x + t1 * r.m_direction.m_x;
00210         const Real pz = r.m_origin.m_z + t1 * r.m_direction.m_z;
00211         const Real d2 = sq(px) + sq(pz);    // square of the distance to the Y axis
00212 
00213         if(d2 <= 1.0 && d2 >= m_inner_radius2) {
00214             min_t = t1; // the ray intersects the lower cap
00215 
00216             normal.m_x = normal.m_z = 0.0;
00217             normal.m_y = -1.0;
00218         }
00219     }
00220 
00221     // Conclude.
00222 
00223     if(min_t == std::numeric_limits<Real>::max())
00224         return false;   // the ray does not intersect the ring
00225 
00226     // The ray does intersect the ring.
00227     ++context.m_statistics->m_intersections_found;
00228 
00229     if(hit) {
00230         min_t *= inv_scale;
00231 
00232         hit->m_object = this;
00233         hit->m_abscissa = min_t;            // world space
00234         hit->m_geometric_normal = normal;   // object space
00235         hit->m_shading_normal = normal;     // object space
00236 
00237         // Normals will be made unit-length later, when absolutely necessary.
00238     }
00239 
00240     return true;
00241 }

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