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 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; }
Segments CSGNode::intersectLocal(const ray& r) const{ Segments ret; if (isLeaf){ SegmentPoint pNear, pFar; isect i; ray backR(r.at(-10000), r.getDirection()); if(!item->intersect(backR, i))return ret; pNear.t = i.t - 10000; pNear.normal = i.N; pNear.isRight = false; ray contiR(r.at(pNear.t+RAY_EPSILON*10),r.getDirection()); if (!item->intersect(contiR, i))pFar = pNear; else { pFar.t = i.t + pNear.t; pFar.normal = i.N; } pFar.isRight = true; ret.addPoint(pNear); ret.addPoint(pFar); return ret; } else { if (!lchild || !rchild)return ret; Segments leftSeg, rightSeg; leftSeg = lchild->intersectLocal(r); rightSeg = rchild->intersectLocal(r); leftSeg.Merge(rightSeg,relation); return leftSeg; } }
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; }
// 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 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 Blinn-Phong model to this point on the surface of the object, // returning the color of that point. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i ) const { // YOUR CODE HERE // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the Phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // You will need to call both distanceAttenuation() and shadowAttenuation() // somewhere in your code in order to compute shadows and light falloff. if (debugMode) std::cout << "Debugging the Phong code (or lack thereof...)" << std::endl; // When you're iterating through the lights, // you'll want to use code that looks something // like this: Vec3d light = ke(i); Vec3d normal = i.N; Vec3d iDot = r.at(i.t); if (r.getDirection() * normal > 0) { normal = -normal; light += prod(prod(scene->ambient(), ka(i)), kt(i)); } else { light += prod(scene->ambient(), ka(i)); } for (vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr) { Light* pLight = *litr; double distAttenuation = pLight->distanceAttenuation(iDot); Vec3d shadowAttenuation = pLight->shadowAttenuation(iDot); Vec3d atten = distAttenuation * shadowAttenuation; Vec3d L = pLight->getDirection(iDot); if (L * normal > 0) { Vec3d H = (L + -1 * r.getDirection()); if (H.length() != 0) H.normalize(); double sDot = max(0.0, normal * H); Vec3d dTerm = kd(i) * (normal * L); Vec3d sTerm = ks(i) * (pow(sDot, shininess(i))); Vec3d newLight = dTerm + sTerm; newLight = prod(newLight, pLight->getColor()); light += prod(atten, newLight); } } return light; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade(Scene *scene, const ray& r, const isect& i) const { const Material& m = i.getMaterial(); Vec3d I = m.ke(i) + prod(m.ka(i) ,scene->ambient()); Vec3d R = 2*(-r.getDirection() * i.N)*i.N +r.getDirection(); for ( vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr ) { Vec3d atten = (*litr)->distanceAttenuation(r.at(i.t)) * (*litr)->shadowAttenuation(r,r.at(i.t)); I += prod(atten,(m.kd(i)*max((i.N * (*litr)->getDirection(r.at(i.t)) ), 0.0) + m.ks(i) * max(((scene->getCamera().getEye() - r.at(i.t)) *R),0.0))); } // You will need to call both the distanceAttenuation() and // shadowAttenuation() methods for each light source in order to // compute shadows and light falloff. return I; }
double surface_planeDIY::hit(const ray &emission_ray, const surface **hit_surface_ptr) const { double t = surface_plane::hit(emission_ray, hit_surface_ptr); point3D hit_point; double x, y; if (t < epsilon) return -1; hit_point = emission_ray.at(t); x = (hit_point - point_on_plane) * axis_x; y = (hit_point - point_on_plane) * axis_y; if (fn(x, y)) return t; return -1; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. vec3f Material::shade( Scene *scene, const ray& r, const isect& i ) const { // YOUR CODE HERE // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // You will need to call both distanceAttenuation() and shadowAttenuation() // somewhere in your code in order to compute shadows and light falloff. //intersection point vec3f point = r.at(i.t); bool istransmissive = abs(index - 1.0) > NORMAL_EPSILON || !kt.iszero(); vec3f rate = vec3f(1, 1, 1) - kt; vec3f I = ke; //ambient if (istransmissive) I += scene->ambient.time(ka).time(rate).clamp(); else I += scene->ambient.time(ka).clamp(); list<Light*>::const_iterator begin = scene->beginLights(); list<Light*>::const_iterator end = scene->endLights(); while (begin != end) { vec3f atten = (*begin)->shadowAttenuation(point) * (*begin)->distanceAttenuation(point); vec3f L = (*begin)->getDirection(point); double NL = i.N.dot(L); //diffuse if (istransmissive) I += (atten * NL).time(kd).time(rate).clamp(); else I += (atten * NL).time(kd).clamp(); //specular vec3f R = i.N * (2 * NL) - L; double RV = -R.dot(r.getDirection()); //TODO: where is n£¿ double n = 64; I += (atten * pow(RV, n)).time(ks).clamp(); begin++; } return I; }
//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; }
intersection_context surface_mobius::intersect(const ray &emission_ray) const { if (!collision_test(emission_ray)) { return null_intersect; } double ox = emission_ray.origin.x; double oy = emission_ray.origin.y; double oz = emission_ray.origin.z; double dx = emission_ray.dir.x; double dy = emission_ray.dir.y; double dz = emission_ray.dir.z; double R = radius; double coef_0 = 0, coef_1 = 0, coef_2 = 0, coef_3 = 0; coef_0 = ox * ox * oy + oy * oy * oy - 2 * ox * ox * oz - 2 * oy * oy * oz + oy * oz * oz - 2 * ox * oz * R - oy * R * R; coef_1 = dy * ox * ox - 2 * dz * ox * ox + 2 * dx * ox * oy + 3 * dy * oy * oy - 2 * dz * oy * oy - 4 * dx * ox * oz - 4 * dy * oy * oz + 2 * dz * oy * oz + dy * oz * oz - 2 * dz * ox * R - 2 * dx * oz * R - dy * R * R; coef_2 = 2 * dx * dy * ox - 4 * dx * dz * ox + dx * dx * oy + 3 * dy * dy * oy - 4 * dy * dz * oy + dz * dz * oy - 2 * dx * dx * oz - 2 * dy * dy * oz + 2 * dy * dz * oz - 2 * dx * dz * R; coef_3 = dx * dx * dy + dy * dy * dy - 2 * dx * dx * dz - 2 * dy * dy * dz + dy * dz * dz; std::vector<double> coef, result; coef.push_back(coef_0); coef.push_back(coef_1); coef.push_back(coef_2); coef.push_back(coef_3); result = equation_solve(coef, 3); for (std::vector<double>::iterator iter = result.begin(); iter != result.end(); ++iter) { if (*iter > epsilon && inside(emission_ray.at(*iter))) { return intersection_context(*iter); } } return null_intersect; }
//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; }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. vec3f RayTracer::traceRay( Scene *scene, const ray& r, const vec3f& thresh, int depth ) { isect i; const double maxDepth = TraceUI::getInstance()->getDepth(); if (scene->intersect(r, i)) { // YOUR CODE HERE // An intersection occured! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); if (isLeavingObject(&m)) { i.N = -i.N; // Normal has to be flipped when leaving object } vec3f result = m.shade(scene, r, i); if (depth < maxDepth) { //reflection const vec3f& u = r.getDirection(); //ray direction const vec3f& refl_dir = (u - 2.0 * u.dot(i.N) * i.N).normalize(); //reflection direction const vec3f& isect_pos = r.at(i.t); //intersection point //new ray, push forward a bit to avoid intersect itself const ray refl_r(isect_pos + refl_dir * RAY_EPSILON, refl_dir); const vec3f& refl_contri = prod(m.kr, traceRay(scene, refl_r, thresh, depth + 1)); result = result + refl_contri; //refraction if (!m.kt.iszero()) { double eta; if (isLeavingObject(&m)) { material_stack.pop_front(); eta = m.index / material_stack.front()->index; // refraction index ratio } else { eta = material_stack.front()->index / m.index; // refraction index ratio material_stack.push_front(&m); } const double k = 1.0 - eta * eta * (1.0 - u.dot(i.N) * u.dot(i.N)); if (!(k < 0.0)) { // k < 0.0 = internal reflection const vec3f& refr_dir = eta * u - (eta * u.dot(i.N) + sqrt(k)) * u; const ray refr_r(isect_pos + refr_dir * RAY_EPSILON, refr_dir); const vec3f& refr_contri = prod(m.kt, traceRay(scene, refr_r, thresh, depth + 1)); result = result + refr_contri; } } } return result; } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. return vec3f( 0.0, 0.0, 0.0 ); } }
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; }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. Vec3d RayTracer::traceRay(ray& r, int depth) { isect i; Vec3d colorC; if(scene->intersect(r, i)) { const Material& m = i.getMaterial(); colorC = m.shade(scene, r, i); if(depth <= 0) return colorC; Vec3d q = r.at(i.t); Vec3d rayDir = -1 * r.getDirection(); rayDir.normalize(); //REFLECTION Vec3d reflectionIntensity = m.kr(i); Vec3d reflectDir = 2 * (rayDir * i.N) * i.N - rayDir; reflectDir.normalize(); ray reflected(q, reflectDir, ray::REFLECTION); reflectionIntensity %= traceRay(reflected, depth - 1); colorC += reflectionIntensity; //END REFLECTION //REFRACTION Vec3d refractionIntensity = m.kt(i); double indexRatio, flip; if(refractionIntensity[0] <= 0.0 && refractionIntensity[1] <= 0.0 && refractionIntensity[2] <= 0.0) { return colorC; } if(i.N * r.getDirection() < 0.0) { indexRatio = 1.0 / m.index(i); flip = -1; } else { indexRatio = m.index(i) / 1.0; flip = 1; } //Check for TIR if(i.N * r.getDirection() > 0.0f) { double iAngle = i.N * r.getDirection(); if((1 - (indexRatio*indexRatio*(1.0f - iAngle * iAngle))) < 0.0) return colorC; } Vec3d rayNormalPart = (rayDir * i.N) * i.N; Vec3d rayTangentialPart = rayNormalPart - rayDir; Vec3d refractTangential = (indexRatio) * rayTangentialPart; double temp = refractTangential * refractTangential; if(temp > 1) temp = 0; Vec3d refractNormal = (flip * i.N) * sqrt( 1.0 - temp); Vec3d refractDir = refractNormal + refractTangential; reflectDir.normalize(); ray refracted(q, refractDir, ray::REFRACTION); refractionIntensity %= traceRay(refracted, depth - 1); colorC += refractionIntensity; //END REFRACTION } else { //do cube mapping? if(!traceUI->doCubeMap()) return Vec3d(0,0,0); TextureMap* texture; double u, v; Vec3d direction = r.getDirection(); double x = direction.n[0]; double y = direction.n[1]; double z = direction.n[2]; double max = std::abs(x); if(std::abs(y) > max) max = std::abs(y); if(std::abs(z) > max) max = std::abs(z); if(max == std::abs(x)) { if(x < 0) { texture = cubeMap->getXnegMap(); u = ((z/std::abs(x)) + 1)/2; v = ((y/std::abs(x)) + 1)/2; } else { texture = cubeMap->getXposMap(); u = ((-z/std::abs(x)) + 1)/2; v = ((y/std::abs(x)) + 1)/2; } } else if(max == std::abs(y)) { if(y < 0) { texture = cubeMap->getYnegMap(); u = ((x/std::abs(y)) + 1)/2; v = ((z/std::abs(y)) + 1)/2; } else { texture = cubeMap->getYposMap(); u = ((x/std::abs(y)) + 1)/2; v = ((-z/std::abs(y)) + 1)/2; } } else { if(z < 0) { texture = cubeMap->getZnegMap(); u = ((-x/std::abs(z)) + 1)/2; v = ((y/std::abs(z)) + 1)/2; } else { texture = cubeMap->getZposMap(); u = ((x/std::abs(z)) + 1)/2; v = ((y/std::abs(z)) + 1)/2; } } colorC = texture->getMappedValue(Vec2d(u,v)); } return colorC; }
vec3f RayTracer::traceRay( Scene *scene, const ray& r, const vec3f& thresh, int depth, isect& i, vector<const SceneObject*>& stack ) { if( depth>=0 && thresh[0] > threshold - RAY_EPSILON && thresh[1] > threshold - RAY_EPSILON && thresh[2] > threshold - RAY_EPSILON && scene->intersect( r, i ) ) { // YOUR CODE HERE // An intersection occured! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); vec3f color = m.shade(scene, r, i); //calculate the reflected ray vec3f d = r.getDirection(); vec3f position = r.at(i.t); vec3f direction = d - 2 * i.N * d.dot(i.N); ray newray(position, direction); if(!m.kr.iszero()) { vec3f reflect = m.kr.multiply(traceRay(scene, newray, thresh.multiply(m.kr), depth-1, stack).clamp()); color += reflect; } //calculate the refracted ray double ref_ratio; double sin_ang = d.cross(i.N).length(); vec3f N = i.N; //Decide going in or out const SceneObject *mi = NULL, *mt = NULL; int stack_idx = -1; vector<const SceneObject*>::reverse_iterator itr; //1 use the normal to decide whether to go in or out //0: travel through, 1: in, 2: out char travel = 0; if(i.N.dot(d) <= -RAY_EPSILON) { //from outer surface in //test whether the object has two face ray test_ray(r.at(i.t) + d * 2 * RAY_EPSILON, -d); isect test_i; if(i.obj->intersect(r, test_i) && test_i.N.dot(N) > -RAY_EPSILON) { //has interior travel = 1; } } else { travel = 2; } if(travel == 1) { if(!stack.empty()) { mi = stack.back(); } mt = i.obj; stack.push_back(mt); } else if(travel == 2) { //if it is in our stack, then we must pop it for(itr = stack.rbegin(); itr != stack.rend(); ++itr) { if(*itr == i.obj) { mi = *itr; vector<const SceneObject*>::iterator ii = itr.base() - 1; stack_idx = ii - stack.begin(); stack.erase(ii); break; } } if(!stack.empty()) { mt = stack.back(); } } if(N.dot(d) >= RAY_EPSILON) { N = -N; } ref_ratio = (mi?(mi->getMaterial().index):1.0) / (mt?(mt->getMaterial().index):1.0); if(!m.kt.iszero() && (ref_ratio < 1.0 + RAY_EPSILON || sin_ang < 1.0 / ref_ratio + RAY_EPSILON)) { //No total internal reflection //We do refraction now double c = N.dot(-d); direction = (ref_ratio * c - sqrt(1 - ref_ratio * ref_ratio * (1 - c * c))) * N + ref_ratio * d; newray = ray(position, direction); vec3f refraction = m.kt.multiply(traceRay(scene, newray, thresh.multiply(m.kt), depth-1, stack).clamp()); color += refraction; } if(travel == 1) { stack.pop_back(); } else if(travel == 2) { if(mi) { stack.insert(stack.begin() + stack_idx, mi); } } return color; } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. if(m_bBackground && bg) { double u, v; angleToSphere(r.getDirection(), u, v); //Scale to [0, 1]; u /= 2 * M_PI; v /= M_PI; int tx = int(u * bg_width), ty = bg_height - int(v * bg_height); return vec3f(bg[3 * (ty * bg_width + tx)] / 255.0, bg[3 * (ty * bg_width + tx) + 1] / 255.0, bg[3 * (ty * bg_width + tx) + 2] / 255.0); } else { return vec3f( 0.0, 0.0, 0.0 ); } } }
// Apply the Phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i, bool isInAir ) const { // YOUR CODE HERE // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the Phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // You will need to call both distanceAttenuation() and shadowAttenuation() // somewhere in your code in order to compute shadows and light falloff. // When you're iterating through the lights, // you'll want to use code that looks something // like this: // // for ( vector<Light*>::const_iterator litr = scene->beginLights(); // litr != scene->endLights(); // ++litr ) // { // Light* pLight = *litr; // . // . // . // } const Vec3d point = r.at(i.t); // Start with emitted light. Vec3d shade = ke(i); // Add ambient light effects. Vec3d ambient = prod(ka(i), scene->ambient()); if (!isInAir) { // If shading a point inside an object, ambient light had to pass through the object first. // So apply the transmission factor to the ambient light to account for object's affect on light. ambient = prod(kt(i), ambient); } shade += ambient; // For each light source... for (vector<Light*>::const_iterator literator = scene->beginLights(); literator != scene->endLights(); ++literator) { const Light* light = *literator; const Vec3d lightDirection = light->getDirection(point); const Vec3d shadowAttenuation = light->shadowAttenuation(point); const double distanceAttenuation = light->distanceAttenuation(point); const Vec3d intensity = prod(light->getColor(point), shadowAttenuation * distanceAttenuation); if (debugMode) cerr << "Shadow: " << shadowAttenuation << ", Distance: " << distanceAttenuation << endl; // Calculate diffuse term. const Vec3d diffuseTerm = kd(i) * max(0.0, i.N * lightDirection); // Calculate specular term. const Vec3d reflectionDir = 2.0 * (lightDirection * i.N) * i.N - lightDirection; const Vec3d viewingDir = -r.getDirection(); const Vec3d specularTerm = ks(i) * pow(max(0.0, viewingDir * reflectionDir), shininess(i)); // Apply diffuse and specular terms to light source. shade += prod(intensity, diffuseTerm + specularTerm); if (debugMode) cerr << "Diffuse: " << diffuseTerm << ", Specular: " << specularTerm << endl; } return shade; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade(Scene *scene, const ray& r, const isect& i) const { //YOUR CODE HERE Vec3d part_e = ke(i); Vec3d part_a = ka(i) % scene->ambient(); Vec3d part_ds(0, 0, 0); for ( vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr ) { Light* pLight = *litr; Vec3d N = i.N; Vec3d L = pLight->getDirection(r.at(i.t)); L.normalize(); Vec3d V = r.d; V.normalize(); Vec3d R = 2*max((L*N), 0.0)*N-L; R.normalize(); double ns = shininess(i); Vec3d shadowAttenuation = pLight->shadowAttenuation(r, r.at(i.t)); double distanceAttenuation = min(pLight->distanceAttenuation(r.at(i.t)), 1.0); Vec3d lightIntensity; if(traceUI->shadowSw()){ lightIntensity = pLight->getColor() % shadowAttenuation * distanceAttenuation; }else{ lightIntensity = pLight->getColor() * distanceAttenuation; } part_ds += prod(lightIntensity, (kd(i)*max(N*L, 0.0)+ks(i)*pow(max((-V*R), 0.0), ns))); } return part_e + part_a + part_ds; // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // When you're iterating through the lights, // you'll want to use code that looks something // like this: // // for ( vector<Light*>::const_iterator litr = scene->beginLights(); // litr != scene->endLights(); // ++litr ) // { // Light* pLight = *litr; // . // . // . // } // You will need to call both the distanceAttenuation() and // shadowAttenuation() methods for each light source in order to // compute shadows and light falloff. //return kd(i); }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. Vec3d RayTracer::traceRay( const ray& r, const Vec3d& thresh, int depth ) { if (depth > traceUI->getDepth()) return Vec3d( 0.0, 0.0, 0.0 ); ++depth; isect i; if( scene->intersect( r, i ) ) { // YOUR CODE HERE // An intersection occured! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); Vec3d iPoint = r.at(i.t); // point of intersection /* // --Shadows-- Vec3d shadow = Vec3d(1.0, 1.0, 1.0); //for (vector<Light*>::const_iterator litr = scene->beginLights(); // litr != scene->endLights(); ++litr ) //{ vector<Light*>::const_iterator litr = scene->beginLights(); Light* pLight = *litr; Vec3d shadowDir = pLight->getDirection(iPoint); isect aux; ray shadow_ray (iPoint,shadowDir,ray::SHADOW); if(scene->intersect(shadow_ray, aux)) { const Material& mm = aux.getMaterial(); shadow = prod(shadow, mm.kt(aux)); } //} */ // --Reflection-- Vec3d reflection = Vec3d(0.0,0.0,0.0); if (m.kr(i) != Vec3d(0.0,0.0,0.0)) { Vec3d reflecDir = 2*((-1*r.getDirection()*i.N)*i.N) + r.getDirection(); reflecDir.normalize(); ray ReflRay (iPoint, reflecDir, ray::REFLECTION); reflection = traceRay(ReflRay, Vec3d(1.0,1.0,1.0), depth); // use threshold for(int i=0; i < 3; i++){ if(reflection[i] > thresh[i]){ reflection[i] = 1; } } } // --Refraction-- Vec3d refraction = Vec3d(0.0,0.0,0.0); if (m.kt(i) != Vec3d(0.0,0.0,0.0)) { double IofR = 1.0 / m.index(i); // the index of refraction Vec3d inorm = i.N; Vec3d d = -1.0*r.getDirection(); // reverse the ray direction for calculations double cos_i = inorm*d; // if the ray is inside of the object if (cos_i < 0.0) { IofR = m.index(i); cos_i *= -1.0; inorm *= -1.0; } double cos_t = 1.0 - (IofR*IofR)*(1.0 - (cos_i*cos_i)); // if not Total Internal Reflection if (cos_t >= 0.0) { Vec3d refractDir = (IofR*cos_i - sqrt(cos_t))*inorm - IofR*d; refractDir.normalize(); ray RefrRay (iPoint, refractDir, ray::REFRACTION); refraction = traceRay(RefrRay, Vec3d(1.0,1.0,1.0), depth); // use threshold for(int i=0; i < 3; i++){ if(refraction[i] > thresh[i]){ refraction[i] = 1; } } } } return m.shade(scene, r, i) + prod(m.kr(i), reflection) + prod(m.kt(i), refraction); } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. return Vec3d( 0.0, 0.0, 0.0 ); } }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i ) const { // YOUR CODE HERE // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // You will need to call both distanceAttenuation() and shadowAttenuation() // somewhere in your code in order to compute shadows and light falloff. if( debugMode ) std::cout << "Debugging Phong code..." << std::endl; Vec3d intensity(0.0f,0.0f,0.0f); Vec3d emmisiveIntensity = ke(i); Vec3d ambientIntensity = ka(i); ambientIntensity %= scene->ambient(); // When you're iterating through the lights, // you'll want to use code that looks something // like this: // const Vec3d intersectionPoint = r.at(i.t); const Vec3d blue(0.0f,0.0f,0.4f); const Vec3d yellow(0.4f,0.4f,0.0f); double alpha = 0.2f; double beta = 0.6f; bool bNonRealism = traceUI->nonRealism(); for ( vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr ){ Light* pLight = *litr; Vec3d lightDirection = pLight->getDirection(intersectionPoint); Vec3d surfaceNormal = i.N; surfaceNormal.normalize(); double aLightToNormal = surfaceNormal * lightDirection; Vec3d lightReflectedDirectionCi = (lightDirection*surfaceNormal)*surfaceNormal; Vec3d lightReflectedDirectionSi = lightReflectedDirectionCi - lightDirection; Vec3d lightReflectedDirection = lightReflectedDirectionCi + lightReflectedDirectionSi; lightReflectedDirection.normalize(); double aRayToLight = (-1 * r.getDirection()) * lightReflectedDirection; Vec3d shadowLight(1.0f,1.0f,1.0f); if(bNonRealism){ if(bump(i)[0]!= 2.0f){ Vec3d perturbed = 2.0f*bump(i)-1.0f; perturbed[0] *= traceUI->getBumpScale(); perturbed[1] *= traceUI->getBumpScale(); perturbed %=surfaceNormal; perturbed.normalize(); aLightToNormal = perturbed * lightDirection;} double coolFac = (1.0f+ (-1.0f)* aLightToNormal)/2.0f; double warmFac = 1.0f - coolFac; Vec3d diffuseIntensity = (coolFac * ( blue + kd(i) * alpha)) + (warmFac * ( yellow + kd(i) * beta)); //Vec3d specularIntensity = ks(i) * pLight->getColor(intersectionPoint); shadowLight %= diffuseIntensity; //+ specularIntensity * std::pow(std::max(aRayToLight,0.0),shininess(i))); } else { if(bump(i)[0]!= 2.0f){ Vec3d perturbed = 2.0f*bump(i)-1.0f; perturbed[0] *= traceUI->getBumpScale(); perturbed[1] *= traceUI->getBumpScale(); perturbed %=surfaceNormal; perturbed.normalize(); aLightToNormal = perturbed * lightDirection;} Vec3d diffuseIntensity = kd(i); Vec3d specularIntensity = ks(i); diffuseIntensity%=pLight->getColor(intersectionPoint); specularIntensity%=pLight->getColor(intersectionPoint); shadowLight = pLight->shadowAttenuation(intersectionPoint); shadowLight %= (diffuseIntensity * std::max(aLightToNormal, 0.0) + specularIntensity * std::pow(std::max(aRayToLight,0.0),shininess(i))); } intensity += shadowLight*pLight->distanceAttenuation(intersectionPoint); } return intensity + emmisiveIntensity + ambientIntensity; }
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; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i ) const { if( debugMode ) std::cout << "Debugging Phong code..." << std::endl; Vec3d pos = r.at(i.t); Camera cam = scene->getCamera(); Vec3d view = cam.getEye() - pos; view.normalize(); Vec3d color = Vec3d(0, 0, 0); Vec3d norm = i.N; norm.normalize(); Vec3d reflect = Vec3d(0, 0, 0); Vec3d amb = ka(i); Vec3d diff = kd(i); if (debugMode) cout << diff << endl; Vec3d spec = ks(i); Vec3d emis = ke(i); double shiny = max(shininess(i), 0.0); Vec3d ambIntensity = scene->ambient(); Vec3d diffIntensity = Vec3d(0, 0, 0); Vec3d specIntensity = Vec3d(0, 0, 0); Vec3d shadowTerm = Vec3d(1, 1, 1); Vec3d diffTerm = Vec3d(0, 0, 0); Vec3d specTerm = Vec3d(0, 0, 0); Vec3d ambTerm = prod(amb, ambIntensity); Vec3d shadAtten = Vec3d(0, 0, 0); for ( vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr) { Light* pLight = *litr; Vec3d tColor = Vec3d(0, 0, 0); Vec3d lightDir = Vec3d(0, 0, 0); double distAtten = pLight->distanceAttenuation(pos); shadAtten = pLight->shadowAttenuation(pos); if(shadAtten[0] != -1){ shadowTerm = shadAtten; } lightDir = pLight->getDirection(pos); lightDir.normalize(); tColor = pLight->getColor(tColor); reflect = (2.0 * (lightDir * norm) * norm) - lightDir; reflect.normalize(); diffIntensity = tColor; specIntensity = tColor; // update diffuse term diffTerm[0] += diff[0] * max((lightDir * norm), 0.0) * diffIntensity[0] * shadowTerm[0]; diffTerm[1] += diff[1] * max((lightDir * norm), 0.0) * diffIntensity[1] * shadowTerm[1]; diffTerm[2] += diff[2] * max((lightDir * norm), 0.0) * diffIntensity[2] * shadowTerm[2]; diffTerm = diffTerm * distAtten; // update specular term specTerm[0] += spec[0] * pow(max((view * reflect),0.0), max(shiny, 0.0)) * specIntensity[0] * shadowTerm[0]; specTerm[1] += spec[1] * pow(max((view * reflect),0.0), max(shiny, 0.0)) * specIntensity[1] * shadowTerm[1]; specTerm[2] += spec[2] * pow(max((view * reflect),0.0), max(shiny, 0.0)) * specIntensity[2] * shadowTerm[2]; specTerm = specTerm * distAtten; // reset the shadowTerm for next loop shadowTerm = Vec3d(1,1,1); } return emis + ambTerm + diffTerm + specTerm; }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. Vec3d RayTracer::traceRay( const ray& r, const Vec3d& thresh, int depth ) { isect i; if( scene->intersect( r, i ) ) { // YOUR CODE HERE // An intersection occured! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); Vec3d ret = m.shade(scene, r, i); if (depth == traceUI->getDepth()) return ret; Vec3d d = r.getDirection(); double n; Vec3d NN = i.N; if (i.N * (-d) >= 0) { // entering the object n = 1.0 / m.index(i); } else { // leaving n = m.index(i); NN = -NN; } double c1 = -(NN * d); Vec3d Rl = d + 2 * NN * c1; ray reflection = ray(r.at(i.t), Rl, r.REFLECTION); ret += prod(m.kr(i), traceRay(reflection, thresh, depth+1)); double c2 = 1 - n*n * (1 - c1*c1); if (c2 >= 0) { // not total internal reflection c2 = sqrt(c2); Vec3d Rr = (n * d) + (n * c1 - c2) * NN; ray refraction = ray(r.at(i.t), Rr, r.REFRACTION); ret += prod(m.kt(i), traceRay(refraction, thresh, depth+1)); } return ret; } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. return Vec3d( 0.0, 0.0, 0.0 ); } }
// Do recursive ray tracing! You'll want to insert a lot of code here // (or places called from here) to handle reflection, refraction, etc etc. vec3f RayTracer::traceRay( Scene *scene, const ray& r, const vec3f& thresh, int depth ) { isect i; vec3f colorC; if (scene->intersect(r, i)) { // YOUR CODE HERE // An intersection occurred! We've got work to do. For now, // this code gets the material for the surface that was intersected, // and asks that material to provide a color for the ray. // This is a great place to insert code for recursive ray tracing. // Instead of just returning the result of shade(), add some // more steps: add in the contributions from reflected and refracted // rays. const Material& m = i.getMaterial(); vec3f intensity = m.shade(scene, r, i); if (depth == 0) return intensity; if (thresh.length() < AdaptiveThreshold) return intensity; vec3f Qpt = r.at(i.t); vec3f minusD = -1 * r.getDirection(); vec3f cosVector = i.N * (minusD * i.N); vec3f sinVector = cosVector + r.getDirection(); vec3f newThresh = thresh; // Reflected Ray if (!m.kr(i).iszero()) { vec3f reflectedDirection = cosVector + sinVector; reflectedDirection.normalize(); ray reflectedRay(Qpt, reflectedDirection, ray::REFLECTION); newThresh = prod(newThresh, i.getMaterial().kr(i)); // change the threshold value intensity = intensity + prod(m.kr(i), traceRay(scene, reflectedRay, newThresh, depth - 1)); } //Refracted Ray if (!m.kt(i).iszero()) { double cosineAngle = acos(i.N * r.getDirection()) * 180 / M_PI; double n_i, n_r; double criticalAngle = 360; int iDirection; // bool goingIn = true; // double cosThetaI = 0; if (cosineAngle > 90) // Coming into an object from air { n_i = 1; n_r = m.index(i); iDirection = 1; // cosThetaI = i.N * -1 * r.d; } else // Going out from object to air { n_i = m.index(i); n_r = 1; // goingIn = false; // cosThetaI = i.N * r.d; iDirection = -1; } double n = n_i / n_r; if (1 - n * n * (1 - (minusD * i.N) * (minusD * i.N)) > 0.0) // NO total internal refraction { vec3f sinT = n * sinVector; // vec3f cosT = (-1 * i.N) * sqrt(1 - sinT*sinT); // not sure if there are any differences between the two eqn, please check!!!!!! vec3f cosT = (-1 * i.N) * sqrt(1 - n * n * (1 - (minusD * i.N) * (minusD * i.N))); vec3f refractedDirection = cosT + iDirection*sinT; refractedDirection.normalize(); ray refractedRay(Qpt, iDirection * refractedDirection, ray::REFRACTION); newThresh = prod(newThresh, i.getMaterial().kt(i)); // change the threshold value intensity = intensity + prod(m.kt(i), traceRay(scene, refractedRay, newThresh, depth - 1)); } } colorC = intensity; } else { // No intersection. This ray travels to infinity, so we color // it according to the background color, which in this (simple) case // is just black. colorC = vec3f (0.0, 0.0, 0.0); } return colorC; }
// Apply the phong model to this point on the surface of the object, returning // the color of that point. Vec3d Material::shade( Scene *scene, const ray& r, const isect& i ) const { // YOUR CODE HERE // For now, this method just returns the diffuse color of the object. // This gives a single matte color for every distinct surface in the // scene, and that's it. Simple, but enough to get you started. // (It's also inconsistent with the phong model...) // Your mission is to fill in this method with the rest of the phong // shading model, including the contributions of all the light sources. // You will need to call both distanceAttenuation() and shadowAttenuation() // somewhere in your code in order to compute shadows and light falloff. if( debugMode ) std::cout << "Debugging Phong code..." << std::endl; //Intersection Point Vec3d P = r.at(i.t); Vec3d L = Vec3d(0,0,0); Vec3d V = -r.getDirection(); //======[ Emission ]====== L += ke(i); if(debugMode) std::cout << "ke(i): " << ke(i) <<"\n"; //======[ Ambient ]====== //missing Ka L += prod(ka(i),scene->ambient()); if(debugMode){ std::cout << "ambient: " << scene->ambient() <<"\n"; std::cout << "ka(i): " << ka(i) <<"\n"; } //iterate through lights for ( std::vector<Light*>::const_iterator litr = scene->beginLights(); litr != scene->endLights(); ++litr ) { Vec3d Lc; //light contribution Light* pLight = *litr; Vec3d sa = pLight->shadowAttenuation(P); double da = pLight->distanceAttenuation(P); //======[ Diffuse ]====== Vec3d direction = pLight->getDirection(P); Vec3d normal = i.N; if(debugMode) { std::cout << "D: "; clamp((normal*direction)*kd(i)).print(); } Lc = clamp((normal*direction)*kd(i)); //======[ Specular ]====== Vec3d H = (V+direction)/2.0; if(debugMode) { std::cout << "S: "; clamp(ks(i)*pow((normal*H),shininess(i))).print(); std::cout <<"sa: "; sa.print(); } Lc += clamp(ks(i)*pow((normal*H),shininess(i))); Lc = da * prod(Lc,sa); L+=Lc; } if(debugMode){ std::cout <<"L: "; L.print(); } return L; }
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; }