Radiance3 RayTracer::L_indirectImpulses(const shared_ptr<Surfel>& surfel, const Vector3& wo, ThreadData& threadData, int bouncesLeft) const { Surfel::ImpulseArray impulseArray; surfel->getImpulses(PathDirection::EYE_TO_SOURCE, wo, impulseArray); Radiance3 L; for (int i = 0; i < impulseArray.size(); ++i) { const Surfel::Impulse& impulse = impulseArray[i]; L += L_in(bump(surfel, impulse.direction), impulse.direction, threadData, bouncesLeft) * impulse.magnitude; } return L; }
Radiance3 App::rayTrace(const Ray& ray, World* world, int bounce) { Radiance3 radiance = Radiance3::zero(); const float BUMP_DISTANCE = 0.0001f; float dist = (float)inf(); const shared_ptr<Surfel>& surfel = world->intersect(ray, dist); if (notNull(surfel)) { // Shade this point (direct illumination) for (int L = 0; L < world->lightArray.size(); ++L) { const shared_ptr<Light>& light = world->lightArray[L]; // Shadow rays if (world->lineOfSight(surfel->location + surfel->geometricNormal * BUMP_DISTANCE, light->position().xyz())) { Vector3 w_i = light->position().xyz() - surfel->location; const float distance2 = w_i.squaredLength(); w_i /= sqrt(distance2); // Biradiance const Biradiance3& B_i = light->color / (4.0f * pif() * distance2); radiance += surfel->finiteScatteringDensity(w_i, -ray.direction()) * B_i * max(0.0f, w_i.dot(surfel->shadingNormal)); debugAssert(radiance.isFinite()); } } // Indirect illumination // Ambient radiance += surfel->reflectivity(m_rng) * world->ambient; // Specular if (bounce < m_maxBounces) { // Perfect reflection and refraction Surfel::ImpulseArray impulseArray; surfel->getImpulses(PathDirection::EYE_TO_SOURCE, -ray.direction(), impulseArray); for (int i = 0; i < impulseArray.size(); ++i) { const Surfel::Impulse& impulse = impulseArray[i]; // Bump along normal *in the outgoing ray direction*. const Vector3& offset = surfel->geometricNormal * sign(impulse.direction.dot(surfel->geometricNormal)) * BUMP_DISTANCE; const Ray& secondaryRay = Ray::fromOriginAndDirection(surfel->location + offset, impulse.direction); debugAssert(secondaryRay.direction().isFinite()); radiance += rayTrace(secondaryRay, world, bounce + 1) * impulse.magnitude; debugAssert(radiance.isFinite()); } } // Add radiance proportional to the distance and fogginess. Divide by 2 so that there isn't too much fog radiance += (radiance.one() * dist * m_fogginess)/2; } else { // Hit the sky radiance = world->ambient; // Add radiance proportional to fogginess. Multiply by 10 so the fog is noticeable radiance += (radiance.one() * m_fogginess * 10); } return radiance; }