NearestIntersection findNearestIntersection(const Scene& scene, const Ray& ray) { NearestIntersection result; for (Scene::ConstIterator it = scene.Begin(); it != scene.End(); it++) { const RayIntersectionPoint& bestIntersection = result.intersection; RayIntersectionPoint intersection = (*it)->getIntersection(ray); if (!intersection.isNull()) { if ((result.isNull()) || intersection.getDistance() < bestIntersection.getDistance()) { result.intersection = intersection; result.primitive = (*it); } } } return result; }
Color trace(const Scene& scene, Ray ray, int depth) { const Color background(0,0,0); const int maxDepth = 3; if (depth >= maxDepth) return background; Color color(0,0,0); double distance = 0; const Primitive* prim = NULL; int intersectionType = 0; findNearsetIntersection(scene, ray, &prim, &distance, &intersectionType); if (prim != NULL) { if (prim->IsIlluminative()) { return prim->GetMaterial().GetColor(); } const Vector3 intersectionPoint = ray.GetPoint(distance); const Vector3 n = prim->GetNormal(intersectionPoint); if (prim->GetMaterial().GetDiffuse() > 0) { for (Scene::ConstIterator it = scene.Begin(); it != scene.End(); it++) { const double intensive = getIntensity((*it), intersectionPoint, n, scene); if (intensive != .0) { Vector3 x = (prim->GetMaterial().GetColor()); Vector3 y = ((*it)->GetMaterial().GetColor()); color = color + (intensive * prim->GetMaterial().GetDiffuse()) * x * y; } } } //refraction { const Vector3 x = ray.GetDirection(); const Vector3 y = intersectionType * (-n); double n; if (intersectionType == IntersectOutside) n = 1.0 / prim->GetMaterial().GetRefractionRate(); else n = prim->GetMaterial().GetRefractionRate(); const double sin_1 = sqrt(1 - Dot(x,y)); const double sin_2 = n * sin_1; if (sin_2 < 1) { const double cos_2 = sqrt(1 - sin_2); Vector3 xPerpendicular = x - Dot(x,y)*y; Vector3 z = cos_2 * y + sin_2 * xPerpendicular; z.Normalize(); if (prim->GetMaterial().GetRefraction() > 0) { if (intersectionType == IntersectInside) { color = color + prim->GetMaterial().GetRefraction() * exp(-prim->GetMaterial().GetAbsorptionRate()*distance) * trace(scene, Ray(intersectionPoint, z), depth + 1); } else color = color + prim->GetMaterial().GetRefraction() * trace(scene, Ray(intersectionPoint, z), depth + 1); } } } //reflection if (prim->GetMaterial().GetReflection() > 0) { const Vector3 a = ray.GetDirection(); Vector3 newA = a - 2 * (Dot(a,n)) * n; color = color + prim->GetMaterial().GetReflection() * trace(scene, Ray(intersectionPoint, newA), depth + 1); } } return color; }