00001 #ifndef SPHERE_H
00002 #define SPHERE_H
00003
00004
00005 #include <cassert>
00006
00007 #include "Primitive.h"
00008
00009
00015 class Sphere : public Primitive
00016 {
00017 public:
00023 Sphere(const Vec3f & center, float radius)
00024 : mCenter(center),
00025 mRadius(radius)
00026 {
00027 assert(radius > 0.0f);
00028 calcBounds();
00029 }
00030
00031 virtual ~Sphere()
00032 {
00033 }
00034
00038 bool intersect(Ray & ray) const
00039 {
00040
00041
00042
00043
00044
00045 Vec3f diff = ray.org() - mCenter;
00046 float a = ray.dir().dot(ray.dir());
00047 float b = 2 * ray.dir().dot(diff);
00048 float c = diff.dot(diff) - mRadius * mRadius;
00049
00050
00051 float inRoot = b*b - 4*a*c;
00052 if (inRoot < 0)
00053 return false;
00054 float root = sqrtf(inRoot);
00055
00056 float dist = (-b - root)/(2*a);
00057 if (dist > ray.t())
00058 return false;
00059
00060 if (dist < EPSILON)
00061 {
00062 dist = (-b + root)/(2*a);
00063 if (dist < EPSILON || dist > ray.t())
00064 return false;
00065 }
00066 ray.setHit(this, dist);
00067
00068
00069
00070 Vec3f hitP = ray.hitPoint(0.0f) - mCenter;
00071 float theta = 1.0f - (atan2f(hitP.y(), hitP.x()) + M_PI)*0.5f/M_PI;
00072 float phi = atan2f(sqrtf(hitP.x()*hitP.x() + hitP.y()*hitP.y()), hitP.z())/M_PI;
00073 ray.setUV(theta, phi);
00074
00075
00076
00077 return true;
00078 }
00079
00084 Vec3f normal(const Ray & ray) const
00085 {
00086 assert(ray.hit() == this);
00087 assert(ray.obj());
00088
00089
00090 float theta = (1.0f - ray.u())*2*M_PI - M_PI;
00091 float phi = ray.v()*M_PI;
00092 Vec3f norm(sinf(phi)*cosf(theta), sinf(phi)*sinf(theta), cosf(phi));
00093 ray.obj()->toGlobalCoordinates(norm);
00094 return norm.normal();
00095 }
00096
00099 virtual TexCoordinate texCoord(const Ray & ray) const
00100 {
00101 return TexCoordinate(ray.u(), ray.v());
00102 }
00103
00107 void axes(const Ray & ray, Vec3f & x, Vec3f & y) const
00108 {
00109 assert(ray.hit() == this);
00110 assert(ray.obj());
00111
00112 Vec3f n = normal(ray);
00113 Vec3f fn = n.fabs();
00114 fn.setX(1 - fn.x());
00115 if (fn.x() <= EPSILON && fn.y() <= EPSILON && fn.z() <= EPSILON)
00116 {
00117 x = Vec3f(0, 1, 0);
00118 y = Vec3f(0, 0, 1);
00119 return;
00120 }
00121 x = - n.cross(Vec3f(1, 0, 0)).normal();
00122 y = n.cross(x).normal();
00123
00124
00125
00126
00127
00128
00129 }
00130
00131 protected:
00133 Vec3f mCenter;
00134
00135
00136 float mRadius;
00137
00138
00141 void calcBounds()
00142 {
00143
00144 mBounds.extend(mCenter + Vec3f(-mRadius));
00145 mBounds.extend(mCenter + Vec3f(mRadius));
00146 }
00147 };
00148
00149
00150 #endif
00151