bool Metaball::intersectLocal(const ray& r, isect& i) const { bool inside = false; if (calvalue(r.getPosition(), ball1pos, ball2pos)>threshold)inside = true; //determine possible intersect range double t11=0, t12=0, t21=0, t22=0; double tmin, tmax; bool i1, i2; i1 = intersectCircle(r, t11, t12, ball1pos); i2 = intersectCircle(r, t21, t22, ball2pos); if (!i1 && !i2) return false; else if (!i1 && i2) { tmin = t21; tmax = t22; } else if (i1 && !i2) { tmin = t11; tmax = t12; } else { tmin = min(t11, t21); tmax = max(t12, t22); } for (double t = tmin; t < tmax; t += 0.001) { vec3f point = r.getPosition() + t * r.getDirection(); double value = calvalue(point, ball1pos, ball2pos); if ((!inside && value > threshold) || (inside && value < threshold)) { // prevent fake intersect if (inside && t < 0.01)return false; vec3f normal; normal += 2 * (point - ball1pos) / ((point - ball1pos).length()*(point - ball1pos).length()); normal += 2 * (point - ball2pos) / ((point - ball2pos).length()*(point - ball2pos).length()); normal = normal.normalize(); i.t = t; i.N = normal; i.obj = this; return true; } } return false; }
// 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 Cone::intersectBody( const ray& r, isect& i ) const { vec3f d = r.getDirection(); vec3f p = r.getPosition(); double a = (d[0]*d[0]) + (d[1]*d[1]) - (C*d[2]*d[2]); double b = 2.0 * (d[0]*p[0] + d[1]*p[1] - C*d[2]*p[2]) - B*d[2]; double c = (p[0]*p[0]) + (p[1]*p[1]) - A - (B*p[2]) - (C*p[2]*p[2]); double disc = b*b - 4.0*a*c; if( disc <= 0.0 ) { return false; } disc = sqrt( disc ); double t1 = (-b - disc) / (2.0 * a); double t2 = (-b + disc) / (2.0 * a); if( t2 < RAY_EPSILON ) { return false; } if( t1 > RAY_EPSILON ) { // Two intersections. vec3f P = r.at( t1 ); double z = P[2]; if( z >= 0.0 && z <= height ) { // It's okay. i.t = t1; double p3 = -C*P[2] + (b_radius - t_radius)*b_radius / height; i.N = vec3f(P[0], P[1], p3).normalize(); #ifdef _DEBUG printf("two intersections!\n"); #endif return true; } } vec3f P = r.at( t2 ); double z = P[2]; if( z >= 0.0 && z <= height ) { i.t = t2; double p3 = -C*P[2] + (b_radius - t_radius)*b_radius / height; i.N = vec3f(P[0], P[1], p3).normalize(); // 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 && (i.N).dot( r.getDirection() ) > 0 ) i.N = -i.N; #ifdef _DEBUG printf("one intersection!\n"); #endif return true; } return false; }
bool intersectCircle(const ray& r0, double& tnear, double& tfar, const vec3f& center) { ray r(r0.getPosition() - center, r0.getDirection()); vec3f v = -r.getPosition(); double b = v.dot(r.getDirection()); double discriminant = b*b - v.dot(v) + 1; if (discriminant < 0.0) { return false; } discriminant = sqrt(discriminant); double t2 = b + discriminant; if (t2 <= RAY_EPSILON) { return false; } double t1 = b - discriminant; if (t1 > RAY_EPSILON) { tnear = t1; tfar = t2; } else { tnear = 0; tfar = t2; } return true; }
bool Sphere::intersectLocal( const 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; 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; }
bool Square::intersectLocal( const ray& r, isect& i ) const { vec3f p = r.getPosition(); vec3f d = r.getDirection(); if( d[2] == 0.0 ) { return false; } double t = -p[2]/d[2]; if( t <= RAY_EPSILON ) { return false; } vec3f 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.t = t; if( d[2] > 0.0 ) { i.N = vec3f( 0.0, 0.0, -1.0 ); } else { i.N = vec3f( 0.0, 0.0, 1.0 ); } return true; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Uses shaddowAttenuation which sends a shadow ray // to check if there is an intersection that blocks the light sources. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i ) const { Vec3d retVal = ke(i) + prod(ka(i), scene->ambient()); // Applies calculations for each light source for (vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr) { Vec3d point = r.getPosition() + r.getDirection() * i.t; Light* pLight = *litr; Vec3d reflectionAngle = 2 * (i.N * pLight->getDirection(point)) * i.N - pLight->getDirection(point); Vec3d diffIntensity = kd(i) * (max(0, i.N * pLight->getDirection(point))); Vec3d viewerAngle = scene->getCamera().getEye() - point; viewerAngle.normalize(); Vec3d specIntensity = ks(i) * pow(max(0, viewerAngle * reflectionAngle), shininess(i)); Vec3d lcolor = pLight->getColor(point); Vec3d totalColor = prod(diffIntensity + specIntensity, lcolor); totalColor = totalColor * pLight->distanceAttenuation(point); totalColor = prod(totalColor, pLight->shadowAttenuation(point)); retVal = retVal + totalColor; } return retVal; }
bool Cylinder::intersectCaps( const ray& r, isect& i ) const { if( !capped ) { return false; } double pz = r.getPosition()[2]; double dz = r.getDirection()[2]; if( 0.0 == dz ) { return false; } double t1; double t2; if( dz > 0.0 ) { t1 = (-pz)/dz; t2 = (1.0-pz)/dz; } else { t1 = (1.0-pz)/dz; t2 = (-pz)/dz; } if( t2 < RAY_EPSILON ) { return false; } if( t1 >= RAY_EPSILON ) { vec3f p( r.at( t1 ) ); if( (p[0]*p[0] + p[1]*p[1]) <= 1.0 ) { i.t = t1; if( dz > 0.0 ) { // Intersection with cap at z = 0. i.N = vec3f( 0.0, 0.0, -1.0 ); } else { i.N = vec3f( 0.0, 0.0, 1.0 ); } return true; } } vec3f p( r.at( t2 ) ); if( (p[0]*p[0] + p[1]*p[1]) <= 1.0 ) { i.t = t2; if( dz > 0.0 ) { // Intersection with cap at z = 1. i.N = vec3f( 0.0, 0.0, 1.0 ); } else { i.N = vec3f( 0.0, 0.0, -1.0 ); } return true; } return false; }
bool Cone::intersectBody( const ray& r, isect& i ) const { vec3f d = r.getDirection(); vec3f p = r.getPosition(); double a = (d[0]*d[0]) + (d[1]*d[1]) - (C*d[2]*d[2]); double b = 2.0 * (d[0]*p[0] + d[1]*p[1] - C*d[2]*p[2]) - B*d[2]; double c = (p[0]*p[0]) + (p[1]*p[1]) - A - (B*p[2]) - (C*p[2]*p[2]); double disc = b*b - 4.0*a*c; if( disc <= 0.0 ) { return false; } disc = sqrt( disc ); double t1 = (-b - disc) / (2.0 * a); double t2 = (-b + disc) / (2.0 * a); if( t2 < RAY_EPSILON ) { return false; } if( t1 > RAY_EPSILON ) { // Two intersections. vec3f P = r.at( t1 ); double z = P[2]; if( z >= 0.0 && z <= height ) { double n3 = -C*P[2] + (b_radius - t_radius)*b_radius / height; i.t = t1; i.N = vec3f( P[0], P[1], n3).normalize(); if (!capped && (i.N).dot(r.getDirection()) > 0) i.N = -i.N; return true; } } vec3f P = r.at( t2 ); double z = P[2]; if( z >= 0.0 && z <= height ) { double n3 = -C*P[2] + (b_radius - t_radius)*b_radius / height; i.t = t2; i.N = vec3f( P[0], P[1], n3).normalize(); if( !capped && (i.N).dot( r.getDirection() ) > 0 ) i.N = -i.N; return true; } return false; }
// if the ray hits the box, put the "t" value of the intersection // closest to the origin in tMin and the "t" value of the far intersection // in tMax and return true, else return false. // Using Kay/Kajiya algorithm. bool BoundingBox::intersect(const ray& r, double& tMin, double& tMax) const { vec3f R0 = r.getPosition(); vec3f Rd = r.getDirection(); tMin = -1.0e308; // 1.0e308 is close to infinity... close enough for us! tMax = 1.0e308; double ttemp; for (int currentaxis = 0; currentaxis < 3; currentaxis++) { double vd = Rd[currentaxis]; // if the ray is parallel to the face's plane (=0.0) if( vd > -RAY_EPSILON && vd < RAY_EPSILON ) { if(R0[currentaxis] <= min[currentaxis] - RAY_EPSILON || R0[currentaxis] >= max[currentaxis] + RAY_EPSILON) { return false; } else { continue; } } double v1 = min[currentaxis] - R0[currentaxis]; double v2 = max[currentaxis] - R0[currentaxis]; // two slab intersections double t1 = v1/vd; double t2 = v2/vd; if ( t1 > t2 ) { // swap t1 & t2 ttemp = t1; t1 = t2; t2 = ttemp; } if (t1 > tMin) tMin = t1; if (t2 < tMax) tMax = t2; if (tMin > tMax) // box is missed return false; if (tMax < -RAY_EPSILON) // box is behind ray return false; } return true; // it made it past all 3 axes. }
bool Box::intersectLocal( const ray& r, isect& i ) const { BoundingBox bounds = ComputeLocalBoundingBox(); vec3f p = r.getPosition(); vec3f d = r.getDirection(); //find tmin and tmax vec3f tmin; vec3f tmax; vec3f nmin(0, 0, 0); vec3f nmax(0, 0, 0); double min; double max; for(int j=0; j<3; j++) { if(d[j]>=0) { tmin[j] = (bounds.min[j] - p[j]) / d[j]; tmax[j] = (bounds.max[j] - p[j]) / d[j]; nmin[j] = -1; nmax[j] = 1; } else { tmin[j] = (bounds.max[j] - p[j]) / d[j]; tmax[j] = (bounds.min[j] - p[j]) / d[j]; nmin[j] = 1; nmax[j] = -1; } } //min of tmax, max of tmin max = std::min( std::min(tmax[0], tmax[1]), tmax[2]); min = std::max( std::max(tmin[0], tmin[1]), tmin[2]); if(min > max || max < RAY_EPSILON) return false; i.obj = this; vec3f N(0, 0, 0); if(min >= RAY_EPSILON) { i.t = min; for(int i=0; i<3; i++) { if(tmin[i] == min) { N[i] = nmin[i]; break; } } } else { i.t = max; for(int i=0; i<3; i++) { if(tmax[i] == max) { N[i] = nmax[i]; break; } } } i.N = N; return true; }
bool Geometry::intersect(const ray&r, isect&i) const { double tmin, tmax; if (hasBoundingBoxCapability() && !(bounds.intersect(r, tmin, tmax))) return false; // Transform the ray into the object's local coordinate space Vec3d pos = transform->globalToLocalCoords(r.getPosition()); Vec3d dir = transform->globalToLocalCoords(r.getPosition() + r.getDirection()) - pos; double length = dir.length(); dir /= length; ray localRay( pos, dir, r.type() ); if (intersectLocal(localRay, i)) { // Transform the intersection point & normal returned back into global space. i.N = transform->localToGlobalCoordsNormal(i.N); i.t /= length; return true; } else return false; }
bool Geometry::intersect(const ray&r, isect&i) const { // Transform the ray into the object's local coordinate space vec3f pos = transform->globalToLocalCoords(r.getPosition()); vec3f dir = transform->globalToLocalCoords(r.getPosition() + r.getDirection()) - pos; double length = dir.length(); dir /= length; ray localRay( pos, dir ); if (intersectLocal(localRay, i)) { // Transform the intersection point & normal returned back into global space. i.N = transform->localToGlobalCoordsNormal(i.N); i.t /= length; return true; } else { return false; } }
//Test // now the object is in the local coordinate rather than the global bool Square::intersectLocal( const ray& r, isect& i ) const { // get the parameters of the ray Vec3d p = r.getPosition(); Vec3d d = r.getDirection(); // if the ray is perpendicular to the z-axis if( d[2] == 0.0 ) { return false; } // calculate the value of t double t = -p[2]/d[2]; // if the intersection is too close to the source // then we don't count that as a intersection 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.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; }
vec3f PointLight::_shadowAttenuation(const vec3f& P, const ray& r) const { double distance = (position - P).length(); vec3f d = r.getDirection(); vec3f result = getColor(P); vec3f curP = r.getPosition(); isect isecP; ray newr(curP, d); while (scene->intersect(newr, isecP)) { //prevent going beyond this light if ((distance -= isecP.t) < RAY_EPSILON) return result; //if not transparent return black if (isecP.getMaterial().kt.iszero()) return vec3f(0, 0, 0); //use current intersection point as new light source curP = r.at(isecP.t); newr = ray(curP, d); result = prod(result, isecP.getMaterial().kt); } return result; }
//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 Sphere::intersectLocal( const ray& r, isect& i ) const { // YOUR CODE HERE: // Add sphere intersection code here. // it currently ignores all spheres and just return false. Vec3d p = r.getPosition(); Vec3d d = r.getDirection(); // a unit sphere double a = d*d; double b = 2.0*(p*d); double c = p*p - 1.0; // d cannot be zero vector actually //if( 0.0 == a ) { // // This implies that x1 = 0.0 and y1 = 0.0, which further // // implies that the ray is aligned with the body of the cylinder, // // so no intersection. // return false; //} // early failure methods: // if the ray and the sphere intersect // then the angle btw rouge and d are \geq 0 Vec3d rouge = Vec3d(0, 0, 0) - p ; rouge.normalize(); double cos_isect = rouge * d ; if ( cos_isect < 0 ) return false; // it seems that the radius of sphere is 1.0 // then we can do the following, calculate the tangent angle // and the compare it with our ray angle towards center of the sphere - origin double cos_tan = sqrt(1 - 1 / rouge.length()); if ( cos_isect < cos_tan ) return false; double discriminant = b*b - 4.0*a*c; if( discriminant < 0.0 ) { return false; } discriminant = sqrt( discriminant ); double t2 = (-b + discriminant) / (2.0 * a); if( t2 <= RAY_EPSILON ) { return false; } double t1 = (-b - discriminant) / (2.0 * a); i.obj = this; if( t1 > RAY_EPSILON ) { // Two intersections. Pick smaller one Vec3d P = r.at( t1 ); double z = P[2]; if( z >= -1.0 && z <= 1.0 ) { // Just check i.t = t1; i.N = Vec3d( P[0], P[1], P[2]); return true; } } return false; }
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; }
bool Cylinder::intersectBody( const ray& r, isect& i ) const { double x0 = r.getPosition()[0]; double y0 = r.getPosition()[1]; double x1 = r.getDirection()[0]; double y1 = r.getDirection()[1]; double a = x1*x1+y1*y1; double b = 2.0*(x0*x1 + y0*y1); double c = x0*x0 + y0*y0 - 1.0; if( 0.0 == a ) { // This implies that x1 = 0.0 and y1 = 0.0, which further // implies that the ray is aligned with the body of the cylinder, // so no intersection. return false; } double discriminant = b*b - 4.0*a*c; if( discriminant < 0.0 ) { return false; } discriminant = sqrt( discriminant ); double t2 = (-b + discriminant) / (2.0 * a); if( t2 <= RAY_EPSILON ) { return false; } double t1 = (-b - discriminant) / (2.0 * a); if( t1 > RAY_EPSILON ) { // Two intersections. vec3f P = r.at( t1 ); double z = P[2]; if( z >= 0.0 && z <= 1.0 ) { // It's okay. i.t = t1; i.N = vec3f( P[0], P[1], 0.0 ).normalize(); return true; } } vec3f P = r.at( t2 ); double z = P[2]; if( z >= 0.0 && z <= 1.0 ) { i.t = t2; vec3f normal( P[0], P[1], 0.0 ); // 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.dot( r.getDirection() ) > 0 ) normal = -normal; i.N = normal.normalize(); return true; } return false; }
bool Box::intersectLocal( const ray& r, isect& i ) const { Vec3d p = r.getPosition(); Vec3d d = r.getDirection(); int it; double x, y, t, bestT; int mod0, mod1, mod2, bestIndex; bestT = HUGE_DOUBLE; bestIndex = -1; for(it=0; it<6; it++){ mod0 = it%3; if(d[mod0] == 0){ continue; } t = ((it/3) - 0.5 - p[mod0]) / d[mod0]; if(t < RAY_EPSILON || t > bestT){ continue; } mod1 = (it+1)%3; mod2 = (it+2)%3; x = p[mod1]+t*d[mod1]; y = p[mod2]+t*d[mod2]; if( x<=0.5 && x>=-0.5 && y<=0.5 && y>=-0.5) { if(bestT > t){ bestT = t; bestIndex = it; } } } if(bestIndex < 0) return false; i.setT(bestT); i.setObject(this); Vec3d intersect_point = r.at(i.t); int i1 = (bestIndex + 1) % 3; int i2 = (bestIndex + 2) % 3; if(bestIndex < 3) { i.setN(Vec3d(-double(bestIndex == 0), -double(bestIndex == 1), -double(bestIndex == 2))); i.setUVCoordinates( Vec2d( 0.5 - intersect_point[ min(i1, i2) ], 0.5 + intersect_point[ max(i1, i2) ] ) ); } else { i.setN(Vec3d(double(bestIndex==3), double(bestIndex == 4), double(bestIndex == 5))); i.setUVCoordinates( Vec2d( 0.5 + intersect_point[ min(i1, i2) ], 0.5 + intersect_point[ max(i1, i2) ] ) ); } return true; }
bool RayIntersectsAABB(const ray& intersectionRay, float* tEntry, float* tExit, const vector4& aabbMinExtents, const vector4& aabbMaxExtents) { // Test against front plane. const vector4& rayPosition = intersectionRay.getPosition(); const vector4& rayDirection = intersectionRay.getDirection(); bool tFound = false; float minimumTValue = FLT_MAX; float maximumTValue = 0.0f; // Containment test. Is the ray inside the aabb? if (rayPosition.extractX() >= aabbMinExtents.extractX() && rayPosition.extractX() <= aabbMaxExtents.extractX() && rayPosition.extractY() >= aabbMinExtents.extractY() && rayPosition.extractY() <= aabbMaxExtents.extractY() && rayPosition.extractZ() >= aabbMinExtents.extractZ() && rayPosition.extractZ() <= aabbMaxExtents.extractZ()) { minimumTValue = 0.0f; tFound = true; } // Intersect ray with the minimum x plane of the aabb. plane minXPlane(vector4(aabbMinExtents.extractX(), 0.0f, 0.0f, 1.0f), vector4(-1.0f, 0.0f, 0.0f, 0.0f)); float minXPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minXPlane, &minXPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minXPlaneIntersection, point); if (point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (minXPlaneIntersection >= 0.0f) tFound = true; if (minXPlaneIntersection < minimumTValue) minimumTValue = minXPlaneIntersection; if (minXPlaneIntersection > maximumTValue) maximumTValue = minXPlaneIntersection; } } // Intersect ray with the maximum x plane of the aabb. plane maxXPlane(vector4(aabbMaxExtents.extractX(), 0.0f, 0.0f, 1.0f), vector4(1.0f, 0.0f, 0.0f, 0.0f)); float maxXPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxXPlane, &maxXPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxXPlaneIntersection, point); if (point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (maxXPlaneIntersection >= 0.0f) tFound = true; if (maxXPlaneIntersection < minimumTValue) minimumTValue = maxXPlaneIntersection; if (maxXPlaneIntersection > maximumTValue) maximumTValue = maxXPlaneIntersection; } } // Intersect ray with the minimum y plane of the aabb. plane minYPlane(vector4(0.0f, aabbMinExtents.extractY(), 0.0f, 1.0f), vector4(0.0f, -1.0f, 0.0f, 0.0f)); float minYPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minYPlane, &minYPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minYPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (minYPlaneIntersection >= 0.0f) tFound = true; if (minYPlaneIntersection < minimumTValue) minimumTValue = minYPlaneIntersection; if (minYPlaneIntersection > maximumTValue) maximumTValue = minYPlaneIntersection; } } // Intersect ray with the maximum y plane of the aabb. plane maxYPlane(vector4(0.0f, aabbMaxExtents.extractY(), 0.0f, 1.0f), vector4(0.0f, 1.0f, 0.0f, 0.0f)); float maxYPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxYPlane, &maxYPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxYPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractZ() >= aabbMinExtents.extractZ() && point.extractZ() <= aabbMaxExtents.extractZ()) { if (maxYPlaneIntersection >= 0.0f) tFound = true; if (maxYPlaneIntersection < minimumTValue) minimumTValue = maxYPlaneIntersection; if (maxYPlaneIntersection > maximumTValue) maximumTValue = maxYPlaneIntersection; } } // Intersect ray with the minimum z plane of the aabb. plane minZPlane(vector4(0.0f, 0.0f, aabbMinExtents.extractZ(), 1.0f), vector4(0.0f, 0.0f, -1.0f, 0.0f)); float minZPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, minZPlane, &minZPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, minZPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY()) { if (minZPlaneIntersection >= 0.0f) tFound = true; if (minZPlaneIntersection < minimumTValue) minimumTValue = minZPlaneIntersection; if (minZPlaneIntersection > maximumTValue) maximumTValue = minZPlaneIntersection; } } // Intersect ray with the maximum z plane of the aabb. plane maxZPlane(vector4(0.0f, 0.0f, aabbMaxExtents.extractZ(), 1.0f), vector4(0.0f, 0.0f, 1.0f, 0.0f)); float maxZPlaneIntersection; if (MathLib::intersectRayWithPlane(intersectionRay, maxZPlane, &maxZPlaneIntersection)) { // Construct the point on the plane. Test if in bounds of the aabb. vector4 point; vector4_addScaledVector(rayPosition, rayDirection, maxZPlaneIntersection, point); if (point.extractX() >= aabbMinExtents.extractX() && point.extractX() <= aabbMaxExtents.extractX() && point.extractY() >= aabbMinExtents.extractY() && point.extractY() <= aabbMaxExtents.extractY()) { if (maxZPlaneIntersection >= 0.0f) tFound = true; if (maxZPlaneIntersection < minimumTValue) minimumTValue = maxZPlaneIntersection; if (maxZPlaneIntersection > maximumTValue) maximumTValue = maxZPlaneIntersection; } } if (tFound) { *tEntry = minimumTValue; *tExit = maximumTValue; } return tFound; }
bool Cone::intersectCaps( const ray& r, isect& i ) const { if( !capped ) { return false; } double pz = r.getPosition()[2]; double dz = r.getDirection()[2]; if( 0.0 == dz ) { return false; } double t1; double t2; double r1; double r2; if( dz > 0.0 ) { t1 = (-pz)/dz; t2 = (height-pz)/dz; r1 = b_radius; r2 = t_radius; } else { t1 = (height-pz)/dz; t2 = (-pz)/dz; r1 = t_radius; r2 = b_radius; } if( t2 < RAY_EPSILON ) { return false; } if( t1 >= RAY_EPSILON ) { vec3f p( r.at( t1 ) ); if( (p[0]*p[0] + p[1]*p[1]) <= r1 * r1 ) { i.t = t1; if( dz > 0.0 ) { // Intersection with cap at z = 0. i.N = vec3f( 0.0, 0.0, -1.0 ); } else { i.N = vec3f( 0.0, 0.0, 1.0 ); } return true; } } vec3f p( r.at( t2 ) ); if( (p[0]*p[0] + p[1]*p[1]) <= r2 * r2 ) { i.t = t2; if( dz > 0.0 ) { // Intersection with interior of cap at z = 1. i.N = vec3f( 0.0, 0.0, 1.0 ); } else { i.N = vec3f( 0.0, 0.0, -1.0 ); } return true; } return false; }
bool Box::intersectLocal(const ray& r, isect& i) const { // YOUR CODE HERE: // Add box intersection code here. // it currently ignores all boxes and just returns false. double iNear = -std::numeric_limits<double>::max(); double iFar = std::numeric_limits<double>::max(); vec3f rayDir = r.getDirection(); vec3f rayPos = r.getPosition(); // t1, t2 is used to compute the intersection distance of the planes double t1 = 0.0f, t2 = 0.0f; int intersect = -1; // for each pair of planes associated with X, Y and Z for (int i = 0; i < 3; i++) { if (rayDir[i] == 0) { if (rayDir[i] < -0.5 || rayDir[i] > 0.5) return false; } t1 = (-0.5 - rayPos[i]) / rayDir[i]; t2 = (0.5 - rayPos[i]) / rayDir[i]; // t1 intersection with near plane if (t1 > t2) { double temp = t2; t2 = t1; t1 = temp; } if (t1 > iNear){ iNear = t1; intersect = i; } if (t2 < iFar) iFar = t2; if (iNear > iFar || iFar < 0) return false; } i.obj = this; i.t = iNear; if (intersect == 0) { if (rayDir[0] < 0.0) i.N = vec3f(1.0, 0.0, 0.0); else i.N = vec3f(-1.0, 0.0, 0.0); } else if (intersect == 1) { if (rayDir[1] < 0.0) i.N = vec3f(0.0, 1.0, 0.0); else i.N = vec3f(0.0, -1.0, 0.0); } else if (intersect == 2) { if (rayDir[2] < 0.0) i.N = vec3f(0.0, 0.0, 1.0); else i.N = vec3f(0.0, 0.0, -1.0); } return true; }