// cast ray and return the color of the closest intersected surface point, // or the background color if there is no object intersection Vector_3D<double> Render_World:: Cast_Ray(Ray& ray,const Ray& parent_ray) { const Object* obj = Closest_Intersection(ray); Vector_3D<double> intersection_point = ray.Point(ray.t_max); //if no object intersection, create dummy variables to satisfy Shader function reqs //and set color to background if (obj == 0) { Vector_3D<double> dummy_vec(0,0,0); Sphere* obj = new Sphere(dummy_vec, 1.0); Vector_3D<double> color = background_shader->Shade_Surface(ray, *obj, dummy_vec, dummy_vec); delete obj; return color; } // call corresponding shader with ray/object information Vector_3D<double> color = obj->material_shader->Shade_Surface(ray, *obj, intersection_point, obj->Normal(intersection_point)); return color; }
double Sphere::RayIntersect(Ray &ray, IntersectData *intersectData) { double A = 1.0; // normalized ray vector double B = 2.0 * (ray.Vector().x * (ray.Point().x - center.x) + ray.Vector().y * (ray.Point().y - center.y) + ray.Vector().z * (ray.Point().z - center.z)); double C = pow(ray.Point().x - center.x, 2.0) + pow(ray.Point().y - center.y, 2.0) + pow(ray.Point().z - center.z, 2.0) - radius * radius; double Det = B * B - 4.0 * A * C; if (Det >= 0.0) { double t = (-B - sqrt(Det)) / 2; if (t > 0.0) { if (intersectData) { Point3D contact = (Vector3D)ray.Point() + ray.Vector() * t; Vector3D normal = (Vector3D)contact - center; normal = normal.Normalize(); intersectData->contact = contact; intersectData->normal = normal; intersectData->color = color; } return t; } t = (-B + sqrt(Det)) / 2; if (t > 0.0) { if (intersectData) { Point3D contact = (Vector3D)ray.Point() + ray.Vector() * t; Vector3D normal = (Vector3D)contact - center; normal = normal.Normalize(); intersectData->contact = contact; intersectData->normal = normal; intersectData->color = color; return t; } } } return INFINITY; }
bool Sphere::Intersect( Ray const &ray, float *tHit, float *epsilon, DifferentialGeometry *geom ) const { Transform tf = Tform(); Ray r = ray * Inverse( tf ); float t; if( !Intersect( ray, &t ) ) return false; // compute differential geometry Vec4 p = ray.Point( t ); float x = p.X(); float y = p.Y(); float z = p.Z(); if( x == 0.0f && z == 0.0f ) { // can't have both atan2 arguments be zero z = kEpsilon * m_radius; } float theta = atan2( p.X(), p.Z() ); if( theta < 0.0f ) { // remap theta to [0, 2pi] to match sphere's definition theta += k2Pi; } float phi = Acos( Clamp( z / m_radius, -1.0f, 1.0f ) ); // parameterize sphere hit float u = theta * kInv2Pi; float v = phi * kInvPi; float sTheta, cTheta; float sPhi, cPhi; SinCos( theta, &sTheta, &cTheta ); SinCos( phi, &sPhi, &cPhi ); Vec4 dpdu( k2Pi * z, 0.0f, -k2Pi * x, 0.0f ); Vec4 dpdv( kPi * y * sTheta, -kPi * m_radius * sPhi, kPi * y * cTheta, 0.0f ); Vec4 d2pdu2( -k2Pi * k2Pi * x, 0.0f, -k2Pi * k2Pi * z, 0.0f ); Vec4 d2pduv( k2Pi * kPi * y * cTheta, 0.0f, -k2Pi * kPi * y * sTheta, 0.0f ); Vec4 d2pdv2( -kPi * kPi * x, -kPi * kPi * y, -kPi * kPi * z, 0.0f ); // change in normal is computed using Weingarten equations Scalar E = Dot( dpdu, dpdu ); Scalar F = Dot( dpdu, dpdv ); Scalar G = Dot( dpdv, dpdv ); Vec4 N = Normalize( Cross( dpdu, dpdv ) ); Scalar e = Dot( N, d2pdu2 ); Scalar f = Dot( N, d2pduv ); Scalar g = Dot( N, d2pdv2 ); Scalar h = 1.0f / ( E * G - F * F ); Vec4 dndu = ( f * F - e * G ) * h * dpdu + ( e * F - f * E ) * h * dpdv; Vec4 dndv = ( g * F - f * G ) * h * dpdu + ( f * F - g * E ) * h * dpdv; *tHit = t; *epsilon = 5e-4f * t; // return world space differential geometry *geom = DifferentialGeometry( Handle(), p * tf, dpdu * tf, dpdv * tf, Normal( dndu ) * tf, Normal( dndv ) * tf, u, v ); return true; }