00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ring.h"
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>
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 ) :
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
00059 m_aabb.Extend(OBJECT_AABB_EXTENSION);
00060 }
00061
00062 Real Ring::ComputeSurfaceArea() const {
00063
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
00075 assert(!"Not implemented yet.");
00076 }
00077
00078 bool Ring::Intersect(const Context &context,
00079 const Ray &ray,
00080 Hit *hit ) const
00081 {
00082
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
00092 r.m_direction *= inv_scale;
00093
00094 Real min_t = std::numeric_limits<Real>::max();
00095 Vector3 normal;
00096
00097
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;
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
00108 const Real t0 = (-c - sqrt_delta0) / a;
00109 const Real t1 = (-c + sqrt_delta0) / a;
00110
00111 if(t0 >= 0.0) {
00112
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;
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
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;
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
00141
00142 const Real b1 = sq(r.m_origin.m_x) + sq(r.m_origin.m_z) - m_inner_radius2;
00143
00144 const Real delta1 = sq(c) - a * b1;
00145
00146 if(delta1 >= 0.0) {
00147 const Real sqrt_delta1 = sqrt(delta1);
00148
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
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;
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
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;
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
00182
00183
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
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);
00192
00193 if(d2 <= 1.0 && d2 >= m_inner_radius2) {
00194 min_t = t0;
00195
00196 normal.m_x = normal.m_z = 0.0;
00197 normal.m_y = 1.0;
00198 }
00199 }
00200
00201
00202
00203
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
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);
00212
00213 if(d2 <= 1.0 && d2 >= m_inner_radius2) {
00214 min_t = t1;
00215
00216 normal.m_x = normal.m_z = 0.0;
00217 normal.m_y = -1.0;
00218 }
00219 }
00220
00221
00222
00223 if(min_t == std::numeric_limits<Real>::max())
00224 return false;
00225
00226
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;
00234 hit->m_geometric_normal = normal;
00235 hit->m_shading_normal = normal;
00236
00237
00238 }
00239
00240 return true;
00241 }