Vec3f RayTracer::shadow(const Vec3f &point, const Vec3f &pointOnLight, const Face *f, const Ray &ray, const Hit &hit) const { const Vec3f normal(hit.getNormal()); const Material *m = hit.getMaterial(); Vec3f dirToLight = pointOnLight - point; dirToLight.Normalize(); /* If dot product < 0, surface is not facing light */ if (normal.Dot3(dirToLight) > 0) { Ray rayToLight(point, dirToLight); Hit hLight; bool blocked = CastRay(rayToLight, hLight, false); while (std::fabs(hLight.getT()) < SURFACE_EPSILON && std::fabs((pointOnLight - point).Length()) > SURFACE_EPSILON) { rayToLight = Ray(rayToLight.pointAtParameter(SURFACE_EPSILON), dirToLight); blocked = CastRay(rayToLight, hLight, false); } if (hLight.getT() == FLT_MAX || hLight.getMaterial() != f->getMaterial()) { return Vec3f(0, 0, 0); } const Vec3f lightColor = 0.2 * f->getMaterial()->getEmittedColor() * f->getArea(); return m->Shade(ray,hit,dirToLight,lightColor,args); } return Vec3f(0, 0, 0); }
bool Raytracer::isInShadow(const SurfaceSample& intersector, const Vector3 w_i, const float lightDistance) const { bool returnValue = false; if (_settings._shadowCast) { // Check if in Shadow, cast ray backwards, up to distance to light.... Ray rayToLight(intersector.shadingLocation + (intersector.shadingNormal * 0.0001f), (w_i.unit())); Tri::Intersector shadowIntersector; float shadowDistance = lightDistance; if (_triTree.intersectRay(rayToLight, shadowIntersector, shadowDistance)) { returnValue = true; } } return returnValue; }
void shade(const Scene * scene, const int level, const C_FLT weight, const Ray &ray, Intercept * intercepts, Color * color) { Material * entryMat = intercepts[0].material, * hitMat = intercepts[0].enter? intercepts[0].primitive->material: ray.medium; C_FLT specWeight = hitMat->specular.magnitude() * weight, transWeight = hitMat->transmission.magnitude() * weight; Vector3D specDir, transDir, normal; std::vector<P_FLT> mapping; Point3D interceptPoint = ray.rayPoint(intercepts[0].t); intercepts[0].primitive->getIntersect(interceptPoint, &normal, &mapping); if (dotProduct(ray.dir, normal) > 0.0f) { normal.negate(); } specularDirection(ray.dir, normal, &specDir); bool transmission = transmissionDirection(entryMat, hitMat, ray.dir, normal, &transDir); *color += scene->ambience * hitMat->ambience; for (std::vector<Light *>::const_iterator itr = scene->lights.begin(); itr != scene->lights.end(); itr++) { Vector3D pointToLight = (*itr)->orig - interceptPoint; P_FLT distanceToLight = pointToLight.normalize(); Ray rayToLight(interceptPoint, pointToLight, NULL); P_FLT lightDotNormal = dotProduct(pointToLight, normal); if (fGreaterZero(lightDotNormal) && fGreaterZero(shadow(scene, rayToLight, distanceToLight))) { // Light source diffuse reflection *color += (*itr)->color * hitMat->diffuse * lightDotNormal; // Light source specular reflection Vector3D h = pointToLight - ray.dir; h.normalize(); P_FLT specDot = dotProduct(normal, h); if (specDot > 0.0f) { *color += (*itr)->color * hitMat->specular * pow(specDot, hitMat->shine); } } else if (transmission && fLessZero(lightDotNormal) && fLessZero(shadow(scene, rayToLight, distanceToLight))) { // Light source specular transmission C_FLT refrRatio = hitMat->refraction / entryMat->refraction; if (!fEqual(refrRatio, 1.0f)) { Vector3D h_j = (-ray.dir - pointToLight * refrRatio) / (refrRatio - 1); h_j.normalize(); // TODO(kent): Define transmission highlight coefficient *color += (*itr)->color * hitMat->transmission * pow(dotProduct(-normal, h_j), hitMat->shine); } } } if (level < MAX_LEVEL) { // Other body specular reflection if (specWeight > MIN_WEIGHT) { Ray specRay(interceptPoint, specDir, entryMat); Color specColor; trace(scene, level + 1, specWeight, specRay, &specColor); *color += specColor * hitMat->specular; } // Other body specular transmission if (transWeight > MIN_WEIGHT) { if (transmission) { Ray transRay(interceptPoint, transDir, hitMat); Color transColor; trace(scene, level + 1, transWeight, transRay, &transColor); *color += transColor * hitMat->transmission; } else { // TODO(kent): Handle total internal reflection } } } if (intercepts[0].enter && intercepts[0].primitive->texture != NULL) { *color *= intercepts[0].primitive->getTexColor(mapping); } }
Eigen::Vector4d getColor(const Ray &ray, unsigned int recursionLevel, unsigned int transDepth, std::array<int, MAX_DEPTH + 1> &objStack) { BOOST_ASSERT_MSG(std::abs(1 - ray.dir.norm()) < EPSILON, "Got ray with non-unit direction"); const intersection_t isect = getIntersection(ray); int objId; if ((objId = isect.objId) < 0) return Eigen::Vector4d::Zero(); auto &objects = scene.getObjects(); auto &lights = scene.getLights(); Eigen::Vector4d I = Eigen::Vector4d::Zero(); Eigen::Vector4d pointOfIntersection = ray.origin + isect.dist * ray.dir; Eigen::Vector4d N = objects[objId]->getUnitNormal(pointOfIntersection); Eigen::Vector4d V = -1 * ray.dir; auto mat = scene.getMaterial(objects[objId]->matId); for (unsigned int i = 0 ; i < lights.size(); ++i) { if (lights[i]->isAmbient()) { I += mat.Ka * lights[i]->getAmountOfLight(pointOfIntersection).cwiseProduct(mat.rgb); continue; } Eigen::Vector4d L = lights[i]->getVectorToLight(pointOfIntersection); Ray rayToLight(pointOfIntersection, L, objId); bool lightVisible = true; if (lights[i]->getShadowOn()) { double distToBlockingObject = getIntersection(rayToLight).dist; double distToLight = (pointOfIntersection - lights[i]->getPosition()).norm(); lightVisible = distToBlockingObject <= EPSILON || distToBlockingObject >= distToLight; } if (lightVisible) { /* Diffuse Reflection */ Eigen::Vector4d Il = lights[i]->getAmountOfLight(pointOfIntersection); // Amount of light visible on surface determined by angle to light source double lambertCos = L.dot(N); if (lambertCos > 0) { I += mat.Kd * lambertCos * mat.rgb.cwiseProduct(Il); } else { continue; } /* Specular Reflection */ Eigen::Vector4d reflection = 2 * N.dot(rayToLight.dir) * N - rayToLight.dir; double specCoeff = reflection.dot(V); if (specCoeff > 0) { specCoeff = std::max(0.0, pow(specCoeff, mat.ns)); I += specCoeff * mat.Ks * mat.rgb.cwiseProduct(Il); } } } if (recursionLevel < MAX_DEPTH) { // Work out where in material stack we are int nextTransDepth; int nextObjId; if (objStack[transDepth] == objId) { nextTransDepth = transDepth - 1; nextObjId = objStack[transDepth - 1]; } else { nextTransDepth = transDepth + 1; objStack[nextTransDepth] = objId; nextObjId = objId; } // Compute intensity of reflected ray, if necessary if (reflect && mat.Kr > 0) { Ray reflectionRay(pointOfIntersection, ray.dir - (2 * N.dot(ray.dir)) * N, nextObjId); I += mat.Kr * getColor(reflectionRay, recursionLevel + 1, nextTransDepth, objStack); } // Compute intensity of transmission ray, if necessary if (refract && mat.Kt > 0) { const double etaIncident = (objStack[transDepth] == ID_AIR) ? 1.0 : scene.getMaterial(objects[objStack[transDepth]]->matId).Irefract; double cosThetaI, etaRefract; if (objStack[transDepth] == objId) { // Exiting a material cosThetaI = ray.dir.dot(N); etaRefract = (objStack[transDepth - 1] == ID_AIR) ? 1.0 : scene.getMaterial(objects[objStack[transDepth - 1]]->matId).Irefract; } else { cosThetaI = V.dot(N); etaRefract = scene.getMaterial(objects[objId]->matId).Irefract; } const double n = etaIncident/etaRefract; const double cosThetaR = sqrt(1 - (n * n) * (1 - cosThetaI * cosThetaI)); Ray T(pointOfIntersection, (n * ray.dir - (cosThetaR - n * cosThetaI) * N).normalized(), nextObjId); I += mat.Kt * getColor(T, recursionLevel + 1, nextTransDepth, objStack); } } return I; }