/******************************************************************/ /* This file is part of the homework assignments for CSCI-427/527 */ /* at The College of William & Mary and authored by Pieter Peers. */ /* No part of this file, whether altered or in original form, can */ /* be distributed or used outside the context of CSCI-427/527 */ /* without consent of either the College of William & Mary or */ /* Pieter Peers. */ /******************************************************************/ #include "ray_util.h" #include "random_number.h" #include "recursiveRaytracing.h" ////////////////// // Constructors // ////////////////// recursiveRaytracing::recursiveRaytracing(unsigned int maxDepth, unsigned int samplesPerPixel) { _depth = maxDepth; _samples = samplesPerPixel; } ///////////// // Methods // ///////////// image recursiveRaytracing::render(const scene& s) const { image result(s.getCamera().width(), s.getCamera().height()); // HW5: Implement a recursive ray tracer that shoots '_samples' rays per pixel. // and has a maximum recursion depth of '_depth'. The ray tracer should // only recurse for specular surfaces, and support environment maps and // shadows. // Modifes: nothing. // Returns: rendered image. // for each pixel for (image::size_type y = 0; y < result.height(); y++) { for (image::size_type x = 0; x < result.width(); x++) { // for sample size 1, shoot ray at pixel center if (_samples == 1) { ray r = s.getCamera()(x + 0.5, y + 0.5); result(x, y) = traceRay(s, r, _depth); } else { // for each sample, trace all the rays! color pixel = color(0.0f); for (unsigned int i = 0; i < _samples; i++) { ray r = s.getCamera()(x + random_float(1.0f), y + random_float(1.0f)); pixel += traceRay(s, r, _depth); } result(x, y) = pixel / _samples; } } } return result; } color recursiveRaytracing::traceRay(const scene& s, const ray& r, unsigned int currentDepth) const { color result = color(0.0f); // base case: bail at max depth if (currentDepth == 0) { return color(); } // intersect the scene intersectionPoint ip = s.intersect(r); // if hit, shade pixel if (ip.isHit()) { // for each light source, for (unsigned int l = 0; l < s.numberOfLightsources(); l++) { // connect to light source lightSample ls = s.getLightsource(l).intensityAt(ip.position()); // create shadow ray and intersect with light source ray shadowRay = createRay(ip, ls.directionToLight()); intersectionPoint shadow_ip = s.intersect(shadowRay); // if object not in shadow, shade it if (!(ip.distance(shadow_ip) < ls.distance())) { result += ip.shade(ls); } } // if specular, compute indirect lighting and recurse if (ip.getShaderProperties().specular) { ray reflect_ray = reflectRay(ip); intersectionPoint reflect_ip = s.intersect(reflect_ray); if (reflect_ip.isHit()) { result += (ip.shade(reflect_ray.direction()) * traceRay(s, reflect_ray, --currentDepth)); } else { // if scene has environment map, grab texel color from map if (s.hasEnvironmentMap()) { result += s.evaluateEnvironmentMap(reflect_ray.direction()); } } } } else { // if scene has environment map, grab texel color from map if (s.hasEnvironmentMap()) { result += s.evaluateEnvironmentMap(r.direction()); } } return result; }