// Intersect ray r with the triangle abc. If it hits returns true, // and puts the t parameter, barycentric coordinates, normal, object id, // and object material in the isect object bool TrimeshFace::intersectLocal( const ray& r, isect& i ) const { const Vec3d& a = parent->vertices[ids[0]]; const Vec3d& b = parent->vertices[ids[1]]; const Vec3d& c = parent->vertices[ids[2]]; // tangent vectors Vec3d t1 = b - a; Vec3d t2 = c - a; Vec3d n = crossProd(t1,t2); double D = -n*a; // if the surface is parallel to the ray there is no intersection if(r.getDirection()*n == 0) { return false; } double t = -(n*r.getPosition() + D)/(n*r.getDirection() ); if (t <= RAY_EPSILON) return false; // point of intersection with the same plane (doesn't mean intersection with triangle) p(t)=p+t*d Vec3d p = r.at(t); // triangle area double A = n.length()/2.0; // barycentric coords double wa = crossProd(c-b, p-b).length() / (2.0*A); double wb = crossProd(a-c, p-c).length() / (2.0*A); double wc = crossProd(b-a, p-a).length() / (2.0*A); if((wa >= 0.0) && (wb >= 0.0) && (wc >= 0.0) && (wa+wb+wc-1.0 <= 0.00001)) { i.setT(t); i.setBary(wa, wb, wc); if (parent->normals.size() == 0) { i.setN(n); } else { Vec3d inter_n = wa*parent->normals[ids[0]] + wb*parent->normals[ids[1]] + wc*parent->normals[ids[2]]; inter_n.normalize(); i.setN(inter_n); } i.setObject(this); if (parent->materials.size() == 0) { i.setMaterial(this->getMaterial() ); } else { Material inter_m = wa*(*parent->materials[ids[0]]); inter_m += wb*(*parent->materials[ids[1]]); inter_m += wc*(*parent->materials[ids[2]]); i.setMaterial(inter_m); } return true; } return false; }
bool Sphere::intersectLocal(ray& r, isect& i) const { Vec3d v = -r.getPosition(); double b = v * r.getDirection(); double discriminant = b*b - v*v + 1; if( discriminant < 0.0 ) { return false; } discriminant = sqrt( discriminant ); double t2 = b + discriminant; if( t2 <= RAY_EPSILON ) { return false; } i.obj = this; i.setMaterial(this->getMaterial()); double t1 = b - discriminant; if( t1 > RAY_EPSILON ) { i.t = t1; i.N = r.at( t1 ); i.N.normalize(); } else { i.t = t2; i.N = r.at( t2 ); i.N.normalize(); } return true; }
//Test bool Square::intersectLocal(ray& r, isect& i) const { Vec3d p = r.getPosition(); Vec3d d = r.getDirection(); if( d[2] == 0.0 ) { return false; } double t = -p[2]/d[2]; if( t <= RAY_EPSILON ) { return false; } Vec3d P = r.at( t ); if( P[0] < -0.5 || P[0] > 0.5 ) { return false; } if( P[1] < -0.5 || P[1] > 0.5 ) { return false; } i.obj = this; i.setMaterial(this->getMaterial()); i.t = t; if( d[2] > 0.0 ) { i.N = Vec3d( 0.0, 0.0, -1.0 ); } else { i.N = Vec3d( 0.0, 0.0, 1.0 ); } i.setUVCoordinates( Vec2d(P[0] + 0.5, P[1] + 0.5) ); return true; }
bool Cone::intersectLocal(ray& r, isect& i) const { bool ret = false; const int x = 0, y = 1, z = 2; // For the dumb array indexes for the vectors Vec3d normal; Vec3d R0 = r.getPosition(); Vec3d Rd = r.getDirection(); double pz = R0[2]; double dz = Rd[2]; double a = Rd[x]*Rd[x] + Rd[y]*Rd[y] - beta_squared * Rd[z]*Rd[z]; if( a == 0.0) return false; // We're in the x-y plane, no intersection double b = 2 * (R0[x]*Rd[x] + R0[y]*Rd[y] - beta_squared * ((R0[z] + gamma) * Rd[z])); double c = -beta_squared*(gamma + R0[z])*(gamma + R0[z]) + R0[x] * R0[x] + R0[y] * R0[y]; double discriminant = b * b - 4 * a * c; double farRoot, nearRoot, theRoot = RAY_EPSILON; bool farGood, nearGood; if(discriminant <= 0) return false; // No intersection discriminant = sqrt(discriminant); // We have two roots, so calculate them nearRoot = (-b + discriminant) / ( 2 * a ); farRoot = (-b - discriminant) / ( 2 * a ); // This is confusing, but it figures out which // root is closer and puts into theRoot nearGood = isGoodRoot(r.at(nearRoot)); if(nearGood && (nearRoot > theRoot)) { theRoot = nearRoot; normal = Vec3d((r.at(theRoot))[x], (r.at(theRoot))[y], -2.0 * beta_squared * (r.at(theRoot)[z] + gamma)); } farGood = isGoodRoot(r.at(farRoot)); if(farGood && ( (nearGood && farRoot < theRoot) || farRoot > RAY_EPSILON) ) { theRoot = farRoot; normal = Vec3d((r.at(theRoot))[x], (r.at(theRoot))[y], -2.0 * beta_squared * (r.at(theRoot)[z] + gamma)); } // In case we are _inside_ the _uncapped_ cone, we need to flip the normal. // Essentially, the cone in this case is a double-sided surface // and has _2_ normals if( !capped && (normal * r.getDirection()) > 0 ) normal = -normal; // These are to help with finding caps double t1 = (-pz)/dz; double t2 = (height-pz)/dz; Vec3d p( r.at( t1 ) ); if(capped) { if( p[0]*p[0] + p[1]*p[1] <= b_radius*b_radius) { if(t1 < theRoot && t1 > RAY_EPSILON) { theRoot = t1; if( dz > 0.0 ) { // Intersection with cap at z = 0. normal = Vec3d( 0.0, 0.0, -1.0 ); } else { normal = Vec3d( 0.0, 0.0, 1.0 ); } } } Vec3d q( r.at( t2 ) ); if( q[0]*q[0] + q[1]*q[1] <= t_radius*t_radius) { if(t2 < theRoot && t2 > RAY_EPSILON) { theRoot = t2; if( dz > 0.0 ) { // Intersection with interior of cap at z = 1. normal = Vec3d( 0.0, 0.0, 1.0 ); } else { normal = Vec3d( 0.0, 0.0, -1.0 ); } } } } if(theRoot <= RAY_EPSILON) return false; i.setT(theRoot); normal.normalize(); i.setN(normal); i.obj = this; i.setMaterial(this->getMaterial()); return true; return ret; }