src/raytracer.cc
branchpyrit
changeset 82 930a2d3ecaed
parent 77 dbe8438d5dca
child 83 e3a2a5b26abb
--- a/src/raytracer.cc	Thu Apr 24 10:49:11 2008 +0200
+++ b/src/raytracer.cc	Thu Apr 24 13:55:11 2008 +0200
@@ -27,6 +27,7 @@
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 #include "raytracer.h"
 
 int pyrit_verbosity = 2;
@@ -115,124 +116,148 @@
 	return I;
 }
 
+Colour Raytracer::shader_evalulate(Ray &ray, int depth, Shape *origin_shape,
+	Float nearest_distance, Shape *nearest_shape)
+{
+	Colour col = Colour();
+	Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection
+	Vector3 normal = nearest_shape->normal(P);
+	bool from_inside = false;
+
+	// make shapes double sided
+	if (dot(normal, ray.dir) > 0.0)
+	{
+		normal = - normal;
+		from_inside = true;
+	}
+
+	col = PhongShader_ambient(*nearest_shape->material, P);
+
+	vector<Light*>::iterator light;
+	for (light = lights.begin(); light != lights.end(); light++) {
+		Vector3 jo, L = (*light)->pos - P; // direction vector to light
+		L.normalize();
+		Float L_dot_N = dot(L, normal);
+		if (L_dot_N > 0) {
+			// test if this light is occluded (sharp shadows)
+			if ((*light)->cast_shadows) {
+				Ray shadow_ray = Ray(P, L);
+				Float dist = FLT_MAX;
+				if (top->nearest_intersection(nearest_shape, shadow_ray, dist))
+					continue;
+			}
+
+			// shading function
+			Vector3 R = L - 2.0 * L_dot_N * normal;
+			col += PhongShader_calculate(*nearest_shape->material,
+				P, normal, R, ray.dir, **light);
+		}
+	}
+
+	if (depth < max_depth)
+	{
+		Colour trans_col, refl_col;
+		Float trans = nearest_shape->material->transmissivity;
+		Float refl = nearest_shape->material->reflectivity;
+		const Float cos_i = - dot(normal, ray.dir);
+
+		// reflection
+		if (refl > 0.01)
+		{
+			Vector3 newdir = ray.dir + 2.0 * cos_i * normal;
+			Ray newray = Ray(P, newdir);
+			refl_col = raytrace(newray, depth + 1, nearest_shape);
+		}
+
+		// refraction
+		if (trans > 0.01)
+		{
+			Float n, n1, n2;
+			if (from_inside)
+			{
+				n1 = nearest_shape->material->refract_index;
+				n2 = 1.0;
+				n = n1;
+			}
+			else
+			{
+				n1 = 1.0;
+				n2 = nearest_shape->material->refract_index;
+				n = 1.0 / n2;
+			}
+			const Float sin2_t = n*n * (1 - cos_i*cos_i);
+			if (sin2_t >= 1.0)
+			{
+					// totally reflected
+					refl += trans;
+					trans = 0;
+			}
+			else
+			{
+				const Float cos_t = sqrtf(1 - sin2_t);
+				const Float Rdiv = 1.0/(n1*cos_i + n2*cos_t);
+				const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv;
+				const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv;
+				const Float R = (Rper*Rper + Rpar*Rpar)/2;
+				refl += R*trans;
+				trans = (1-R)*trans;
+				Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal;
+				Ray newray = Ray(P + 0.001*newdir, newdir);
+				trans_col = raytrace(newray, depth + 1, NULL);
+			}
+		}
+		col = (1-refl-trans)*col + refl*refl_col + trans*trans_col;
+	}
+
+	// ambient occlusion
+	if (!from_inside && ao_samples)
+	{
+		Float miss = 0;
+		for (int i = 0; i < ao_samples; i++) {
+			Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal);
+			Ray ao_ray = Ray(P, dir);
+			Float dist = ao_distance;
+			Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist);
+			if (shape_in_way == NULL)
+				miss += 1.0;
+			else
+				miss += dist / ao_distance;
+		}
+		Float ao_intensity = miss / ao_samples;
+		col = col * ao_intensity;
+	}
+
+	return col;
+}
+
 Colour Raytracer::raytrace(Ray &ray, int depth, Shape *origin_shape)
 {
 	Float nearest_distance = Inf;
 	Shape *nearest_shape = top->nearest_intersection(origin_shape, ray, nearest_distance);
 
-	if (nearest_shape == NULL) {
+	if (nearest_shape == NULL)
+	{
 		return bg_colour;
-	} else {
-		Colour col = Colour();
-		Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection
-		Vector3 normal = nearest_shape->normal(P);
-		bool from_inside = false;
-
-		// make shapes double sided
-		if (dot(normal, ray.dir) > 0.0)
-		{
-			normal = - normal;
-			from_inside = true;
-		}
-
-		col = PhongShader_ambient(*nearest_shape->material, P);
-
-		vector<Light*>::iterator light;
-		for (light = lights.begin(); light != lights.end(); light++) {
-			Vector3 jo, L = (*light)->pos - P; // direction vector to light
-			L.normalize();
-			Float L_dot_N = dot(L, normal);
-			if (L_dot_N > 0) {
-				// test if this light is occluded (sharp shadows)
-				if ((*light)->cast_shadows) {
-					Ray shadow_ray = Ray(P, L);
-					Float dist = FLT_MAX;
-					if (top->nearest_intersection(nearest_shape, shadow_ray, dist))
-						continue;
-				}
-
-				// shading function
-				Vector3 R = L - 2.0 * L_dot_N * normal;
-				col += PhongShader_calculate(*nearest_shape->material,
-					P, normal, R, ray.dir, **light);
-			}
-		}
-
-		if (depth < max_depth)
-		{
-			Colour trans_col, refl_col;
-			Float trans = nearest_shape->material->transmissivity;
-			Float refl = nearest_shape->material->reflectivity;
-			const Float cos_i = - dot(normal, ray.dir);
-
-			// reflection
-			if (refl > 0.01)
-			{
-				Vector3 newdir = ray.dir + 2.0 * cos_i * normal;
-				Ray newray = Ray(P, newdir);
-				refl_col = raytrace(newray, depth + 1, nearest_shape);
-			}
+	}
+	else
+	{
+		return shader_evalulate(ray, depth, origin_shape, nearest_distance, nearest_shape);
+	}
+}
 
-			// refraction
-		 	if (trans > 0.01)
-			{
-				Float n, n1, n2;
-				if (from_inside)
-				{
-					n1 = nearest_shape->material->refract_index;
-					n2 = 1.0;
-					n = n1;
-				}
-				else
-				{
-					n1 = 1.0;
-					n2 = nearest_shape->material->refract_index;
-					n = 1.0 / n2;
-				}
-				const Float sin2_t = n*n * (1 - cos_i*cos_i);
-				if (sin2_t >= 1.0)
-				{
-					 // totally reflected
-					 refl += trans;
-					 trans = 0;
-				}
-				else
-				{
-					const Float cos_t = sqrtf(1 - sin2_t);
-					const Float Rdiv = 1.0/(n1*cos_i + n2*cos_t);
-					const Float Rper = (n1*cos_i - n2*cos_t)*Rdiv;
-					const Float Rpar = (n2*cos_i - n1*cos_t)*Rdiv;
-					const Float R = (Rper*Rper + Rpar*Rpar)/2;
-					refl += R*trans;
-					trans = (1-R)*trans;
-					Vector3 newdir = n * ray.dir + (n*cos_i - cos_t) * normal;
-					Ray newray = Ray(P + 0.001*newdir, newdir);
-					trans_col = raytrace(newray, depth + 1, NULL);
-				}
-			}
-			col = (1-refl-trans)*col + refl*refl_col + trans*trans_col;
-		}
+void Raytracer::raytracePacket(Ray *rays, Colour *results)
+{
+	Float nearest_distances[4] = {Inf,Inf,Inf,Inf};
+	Shape *nearest_shapes[4];
+	static const Shape *origin_shapes[4] = {NULL, NULL, NULL, NULL};
+	top->packet_intersection(origin_shapes, rays, nearest_distances, nearest_shapes);
 
-		// ambient occlusion
-		if (!from_inside && ao_samples)
-		{
-			Float miss = 0;
-			for (int i = 0; i < ao_samples; i++) {
-				Vector3 dir = SphereDistribute(i, ao_samples, ao_angle, normal);
-				Ray ao_ray = Ray(P, dir);
-				Float dist = ao_distance;
-				Shape *shape_in_way = top->nearest_intersection(nearest_shape, ao_ray, dist);
-				if (shape_in_way == NULL)
-					miss += 1.0;
-				else
-					miss += dist / ao_distance;
-			}
-			Float ao_intensity = miss / ao_samples;
-			col = col * ao_intensity;
-		}
-
-		return col;
-	}
+	for (int i = 0; i < 4; i++)
+		if (nearest_shapes[i] == NULL)
+			results[i] = bg_colour;
+		else
+			results[i] = shader_evalulate(rays[i], 0, NULL,
+				nearest_distances[i], nearest_shapes[i]);
 }
 
 void *Raytracer::raytrace_worker(void *d)
@@ -242,7 +267,8 @@
 	Sample my_queue[my_queue_size];
 	Colour my_colours[my_queue_size];
 	int my_count;
-	Ray ray;
+	Ray ray, rays[4];
+	const bool can_use_packets = (rt->use_packets && rt->sampler->packetableSamples());
 	for (;;)
 	{
 		pthread_mutex_lock(&rt->sample_queue_mutex);
@@ -282,10 +308,24 @@
 		pthread_mutex_unlock(&rt->sample_queue_mutex);
 
 		// do the work
-		for (int i = 0; i < my_count; i++)
+		if (can_use_packets)
 		{
-			ray = rt->camera->makeRay(my_queue[i]);
-			my_colours[i] = rt->raytrace(ray, 0, NULL);
+			// packet ray tracing
+			assert((my_count % 4) == 0);
+			for (int i = 0; i < my_count; i+=4)
+			{
+				rt->camera->makeRayPacket(my_queue + i, rays);
+				rt->raytracePacket(rays, my_colours + i);
+			}
+		}
+		else
+		{
+			// single ray tracing
+			for (int i = 0; i < my_count; i++)
+			{
+				ray = rt->camera->makeRay(my_queue[i]);
+				my_colours[i] = rt->raytrace(ray, 0, NULL);
+			}
 		}
 
 		// save the results