Sphere.cpp

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @file   Sphere.cpp
00003    @author Travis Fischer (fisch0920@gmail.com)
00004    @author Matthew Jacobs (jacobs.mh@gmail.com)
00005    @date   Fall 2008
00006    
00007    @brief
00008       Representation of a 3D sphere with radius .5, enclosed in the unit box 
00009    (-.5,-.5,-.5) to (.5,.5,.5)
00010    <!-------------------------------------------------------------------->**/
00011 
00012 #include "Sphere.h"
00013 #include <SurfacePoint.h>
00014 
00015 real_t Sphere::getIntersection(const Ray &ray, SurfacePoint &pt) {
00016    Point3  P;
00017    Vector3 D;
00018    _transformRayWorldToObj(ray, P, D);
00019    
00020    // A = (Dx^2 + Dy^2 + Dz^2)
00021    const real_t A = 2 * (D[0] * D[0] + D[1] * D[1] + D[2] * D[2]);
00022    
00023    // B = (2 * Px * Dx + 2 * Py * Dy + 2 * Pz * Dz)
00024    const real_t B = -2 * (P[0] * D[0] + P[1] * D[1] + P[2] * D[2]);
00025    
00026    // C = (Px^2 + Py^s + Pz^2 - 1/4)
00027    const real_t C = (P[0] * P[0] + P[1] * P[1] + P[2] * P[2] - 0.25);
00028    
00029    // Discriminant of quadratic = B^2 - 4 * A * C
00030    real_t discriminant =  B * B - 2 * A * C;
00031    
00032    // Check for intersection with Sphere Body
00033    // ---------------------------------------
00034    if (discriminant < 0)
00035       return INFINITY;
00036    
00037    discriminant = sqrt(discriminant);
00038    const real_t F = 1 / A;
00039    real_t       t = (B - discriminant) * F;
00040    
00041    return ((t > INTERSECT_TOLERANCE || 
00042            (t = (B + discriminant) * F) > INTERSECT_TOLERANCE) 
00043           ? t : INFINITY);
00044 }
00045 
00046 bool Sphere::intersects(const Ray &ray, real_t tMax) {
00047    Point3  P;
00048    Vector3 D;
00049    _transformRayWorldToObj(ray, P, D);
00050    
00051    // A = (Dx^2 + Dy^2 + Dz^2)
00052    const real_t A = 2 * (D[0] * D[0] + D[1] * D[1] + D[2] * D[2]);
00053    
00054    // B = (2 * Px * Dx + 2 * Py * Dy + 2 * Pz * Dz)
00055    const real_t B = -2 * (P[0] * D[0] + P[1] * D[1] + P[2] * D[2]);
00056    
00057    // C = (Px^2 + Py^s + Pz^2 - 1/4)
00058    const real_t C = (P[0] * P[0] + P[1] * P[1] + P[2] * P[2] - 0.25);
00059    
00060    // Discriminant of quadratic = B^2 - 4 * A * C
00061    real_t discriminant =  B * B - 2 * A * C;
00062    
00063    // Check for intersection with Sphere Body
00064    // ---------------------------------------
00065    
00066    if (discriminant >= 0) {
00067       discriminant = sqrt(discriminant);
00068       const real_t F = 1 / A;
00069       
00070       real_t t = (B + discriminant) * F;
00071       return (isValidT(t, tMax) || 
00072               ((t = (B - discriminant) * F) < tMax && t > INTERSECT_TOLERANCE));
00073    }
00074    
00075    return false;
00076 }
00077 
00078 void Sphere::_getUV(SurfacePoint &pt) const {
00079    Point3 P;
00080    _transformPoint3WorldToObj(pt.position, P);
00081    real_t &u = pt.uv.u, &v = pt.uv.v;
00082    
00083    u = 1 - atan2(P[2], P[0]) * (1 / (2 * M_PI));
00084    v = 0.5 - asin(P[1] * 2) * (1 / M_PI);
00085 }
00086 
00087 void Sphere::_getGeometricNormal(SurfacePoint &pt) const {
00088    Point3 P;
00089    _transformPoint3WorldToObj(pt.position, P);
00090    Vector3 nObj(P[0], P[1], P[2]);
00091    
00092    _transformVector3ObjToWorld(nObj, pt.normalG);
00093 }
00094 
00095 void Sphere::preview() {
00096    Transformable::preview();
00097    
00098    if (m_quadric == NULL)
00099       m_quadric = gluNewQuadric();
00100    
00101    ASSERT(m_quadric != NULL);
00102    
00103    gluSphere(m_quadric, 0.5, 20, 20);
00104 }
00105 
00106 void Sphere::getRandomPoint(SurfacePoint &pt) {
00107    if (!m_surfaceSampler)
00108       m_surfaceSampler = new UniformOnSphereSampler();
00109    
00110    pt.position = m_transToWorld * m_surfaceSampler->sample().getValue<Point3>();
00111    _getUV(pt);
00112    
00113    getPoint(pt, pt.uv);
00114 }
00115 
00116 Point3 Sphere::getPosition(const UV &uv) {
00117    real_t x = CAP(tan((1.0 - uv.u) / (2 * M_PI)), -.5, .5);
00118    real_t y = CAP(sin((0.5 - uv.v) / M_PI) * 0.5, -.5, .5);
00119    real_t z = sqrt(1 - x * x - y * y);
00120    
00121    // TODO: verify correctness for x and z (inversing atan2)
00122    return m_transToWorld * Point3(x, y, z);
00123 }
00124 
00125 #if 0
00126 Vector3 Sphere::getNormal(const Point3 &pt) const {
00127    const Point3 &ptObj = m_transToWorldInv * pt;
00128    Vector3 nObj(ptObj.data), nWorld;
00129    
00130    // TODO: shouldn't need to normalize nObj before transformation
00131    _transformVector3ObjToWorld(nObj, nWorld);
00132    
00133    return nWorld;
00134 }
00135 #endif
00136 
00137 real_t Sphere::_getSurfaceArea() {
00138    // TODO return surface area in world-space!!!
00139    return (4 * M_PI * 0.25); // 4*pi*r^2
00140 }
00141 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6