// 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; }
// 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; if( scene->intersectMode( 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 I = m.shade(scene, r, i); if (depth >= maxDepth)return I; if (thresh.length() < maxThresh-RAY_EPSILON)return I; vec3f conPoint = r.at(i.t); vec3f normal; vec3f Rdir = 2 * (i.N*-r.getDirection()) * i.N - (-r.getDirection()); //reflection ray R = ray(conPoint, Rdir); vec3f newThres = prod(thresh, i.getMaterial().kr); if (!i.getMaterial().kr.iszero())I += prod(i.getMaterial().kr, traceRay(scene, R, newThres, depth + 1)); //if not opaque if (!i.getMaterial().kt.iszero()){ bool TIR = false; //refraction ray T(conPoint, r.getDirection());//without refraction bool toAdd = false, toErase = false; //if not surface if (i.obj->hasInterior()){ //calculate angle //in or out double indexA, indexB; if (i.N*r.getDirection() > RAY_EPSILON){//out if (mediaHistory.empty())indexA = 1.0; else indexA = mediaHistory.rbegin()->second.index; mediaHistory.erase(i.obj->getOrder()); toAdd = true; if (mediaHistory.empty())indexB = 1.0; else { indexB = mediaHistory.rbegin()->second.index; } normal = -i.N; } else {//in if (mediaHistory.empty())indexA = 1.0; else indexA = mediaHistory.rbegin()->second.index; mediaHistory.insert(make_pair(i.obj->getOrder(),i.getMaterial())); toErase = true; indexB = mediaHistory.rbegin()->second.index; normal = i.N; } double indexRatio = indexA / indexB; double cdi = normal*-r.getDirection(); double sdi = 1 - cdi*cdi; double sdt = sdi * indexRatio; //sin delta t //TIR if (sdt > 1.0 + RAY_EPSILON){ TIR = true; } else { TIR = false; double cdt = sqrt(1 - sdt*sdt); vec3f Tdir = (indexRatio*cdi - cdt)*normal - indexRatio*-r.getDirection(); T = ray(conPoint, Tdir); } } newThres = prod(thresh, i.getMaterial().kt); if(!TIR)I += prod(i.getMaterial().kt, traceRay(scene, T, newThres, depth + 1)); if (toAdd)mediaHistory.insert(make_pair(i.obj->getOrder(), i.getMaterial())); if (toErase)mediaHistory.erase(i.obj->getOrder()); } I = I.clamp(); return I; } 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 (!useBackground)return vec3f(0.0, 0.0, 0.0); else { vec3f axis_x = scene->getCamera()->getU(); vec3f S = r.getDirection(); S -= (S*axis_x)*axis_x; vec3f axis_z = scene->getCamera()->getLook(); vec3f sz = (S*axis_z) *axis_z; S -= sz; vec3f axis_v = scene->getCamera()->getV(); vec3f axis_y = axis_x.cross(axis_z); double dis_v = (S*axis_y); S = r.getDirection() - dis_v * axis_v; double dis_x = S * axis_x; double dis_z = S * axis_z; vec3f res = dis_x * axis_x + dis_v * axis_v + dis_z * axis_z; return getBackgroundImage(dis_x / dis_z + 0.5, dis_v / dis_z + 0.5); } } }