summaryrefslogtreecommitdiff
path: root/hw6/src/pathtracing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hw6/src/pathtracing.cpp')
-rw-r--r--hw6/src/pathtracing.cpp175
1 files changed, 175 insertions, 0 deletions
diff --git a/hw6/src/pathtracing.cpp b/hw6/src/pathtracing.cpp
new file mode 100644
index 0000000..dc9dda1
--- /dev/null
+++ b/hw6/src/pathtracing.cpp
@@ -0,0 +1,175 @@
+/******************************************************************/
+/* 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 "pathtracing.h"
+#include "random_number.h"
+
+//////////////////
+// Constructors //
+//////////////////
+pathtracing::pathtracing(unsigned int samplesPerPixel, bool directOnly)
+{
+ _samples = samplesPerPixel;
+ _directOnly = directOnly;
+}
+
+
+/////////////
+// Methods //
+/////////////
+image pathtracing::render(const scene& s) const
+{
+ image result(s.getCamera().width(), s.getCamera().height());
+
+ // for every pixel
+ for(image::size_type y=0; y < result.height(); y++)
+ for(image::size_type x=0; x < result.width(); x++)
+ {
+ color pixelRadiance(0.0f, 0.0f, 0.0f);
+
+ // for every sample
+ for(unsigned int sample = 0; sample < _samples; sample++)
+ {
+ color sampleRadiance(0.0f, 0.0f, 0.0f);
+
+ // generate random camera ray through pixel:
+ float px = (float)(x) + random_float(); float py = (float)(y) + random_float();
+ ray r = s.getCamera()(px, py);
+
+ // get initial intersection point
+ intersectionPoint ip = s.intersect(r);
+
+ // get radiance from directly visible *area* light sources
+ if(ip.isHit())
+ sampleRadiance += ip.emittance();
+
+ // get scene radiance
+ sampleRadiance += radiance(s, r, ip);
+
+ // store
+ pixelRadiance += sampleRadiance / (float)(_samples);
+ }
+
+ // store in image
+ result(x,y) = pixelRadiance;
+ }
+
+ // Done.
+ return result;
+}
+
+
+/////////////////////
+// Private Methods //
+/////////////////////
+color pathtracing::radiance(const scene& s, const ray& r, const intersectionPoint& ip) const
+{
+ color radiance(0.0f, 0.0f, 0.0f);
+
+ // if scene hit
+ if(ip.isHit())
+ {
+ // solve rendering equation
+ radiance = directRadiance(s, ip);
+ if(!_directOnly) radiance += indirectRadiance(s, ip);
+ }
+
+ // if not hit
+ else if(s.hasEnvironmentMap())
+ {
+ radiance += s.evaluateEnvironmentMap(r.direction());
+ }
+
+ // Done.
+ return radiance;
+}
+
+
+color pathtracing::directRadiance(const scene& s, const intersectionPoint& ip) const
+{
+ // HW6: implement this. Compute the direct radiance incident
+ // at the intersection point 'ip' according to the
+ // rendering equation.
+ // Modifies: nothing
+ // Returns: computed direct radiance.
+
+ color result = color(0.0f);
+
+ // for every light source,
+ for (int l = 0; l < s.numberOfLightsources(); l++) {
+ // sample the light source
+ lightSample ls = s.getLightsource(l).emittanceAt(ip.position(), random_float(), random_float());
+
+ // check if occluded
+ ray shadowRay = createRay(ip, ls.directionToLight());
+ intersectionPoint shadowIp = s.intersect(shadowRay);
+
+ // if not occluded,
+ if (ls < shadowIp && ls.distance() > sqrt(EPSILON)) {
+ float cosine = ls.directionToLight().dot(ip.normal()) / ls.distance();
+
+ // if no division by zero,
+ if (ls.pdf() > EPSILON && cosine >= 0) {
+ // compute radiance via rendering equation for direct illumination
+ result += (ip.reflectance(ls.directionToLight()) // fr(x, -psi<->theta) (brdf)
+ * ls.emittance() // Le(y->psi)
+ * cosine // cos(nx, -psi)
+ * ls.foreshortening() // cos(ny, psi)
+ / ls.distance() // r^2 (other r in cosine calculation)
+ / ls.pdf() // pdf (monte-carlo integration probability)
+ );
+ }
+
+ }
+
+ }
+
+ return result;
+}
+
+
+color pathtracing::indirectRadiance(const scene& s, const intersectionPoint& ip) const
+{
+ // HW6: implement this. Computed the indirect radiance incident
+ // at the intersection point 'ip' according to the rendering
+ // equation.
+ // Modifies: nothing
+ // Returns: computed indirect radiance.
+
+ color result = color(0.0f);
+
+ // if absorption falls above a random value, end recursion (russian roulette)
+ if (1 - ip.reflectivity() > random_float(1.0f)) { return result; }
+
+ // sample the surface
+ brdfSample brdf = ip.sample(random_float(), random_float());
+
+ // create exitant ray
+ ray exitantRay = createRay(ip, brdf.exitantDirection());
+
+ // recursively compute radiance from reflected point
+ color reflectedColor = radiance(s, exitantRay, s.intersect(exitantRay));
+
+ // compute cosine
+ float cosine = brdf.exitantDirection().dot(ip.normal());
+
+ // if no division by zero via pdf and cosines are not negative,
+ if (brdf.pdf() > EPSILON && cosine > EPSILON) {
+ // compute radiance via rendering equation for indirect illumination
+ result += (brdf.reflectance() // fr(x, -psi<->theta) (brdf)
+ * reflectedColor // Le(y->psi)
+ * cosine // cos(nx, -psi)
+ / brdf.pdf() // pdf (monte-carlo integration probability)
+ / ip.reflectivity() // russian roulette
+ );
+
+ }
+
+ return result;
+}