prepare structures for packet tracing pyrit
authorRadek Brich <radek.brich@devl.cz>
Thu, 24 Apr 2008 13:55:11 +0200
branchpyrit
changeset 82 930a2d3ecaed
parent 81 9dbb9c8c115b
child 83 e3a2a5b26abb
prepare structures for packet tracing (it's already slightly faster, even without any explicit parallelization) supply missing virtual destructors
include/container.h
include/material.h
include/raytracer.h
include/sampler.h
include/scene.h
include/shapes.h
src/container.cc
src/raytracer.cc
src/sampler.cc
--- a/include/container.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/container.h	Thu Apr 24 13:55:11 2008 +0200
@@ -48,6 +48,9 @@
 	//void addShapeNoExtend(Shape* aShape) { shapes.push_back(aShape); };
 	virtual Shape *nearest_intersection(const Shape *origin_shape, const Ray &ray,
 		Float &nearest_distance);
+	virtual void packet_intersection(const Shape **origin_shapes, const Ray *rays,
+		Float *nearest_distances, Shape **nearest_shapes);
+
 	virtual void optimize() {};
 
 	ShapeList & getShapes() { return shapes; };
--- a/include/material.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/material.h	Thu Apr 24 13:55:11 2008 +0200
@@ -51,6 +51,7 @@
 class ColourMap
 {
 public:
+	virtual ~ColourMap() {};
 	virtual Colour map(const Float &val) = 0;
 };
 
@@ -106,6 +107,7 @@
 public:
 	TextureMap(const Vector3 &acenter, const Float &size):
 		center(acenter), invsize(1./size) {};
+	virtual ~TextureMap() {};
 	virtual void map(const Vector3 &point, Float &u, Float &v) = 0;
 };
 
@@ -257,7 +259,7 @@
 		u -= floor(u);
 		v = -(v - 0.5);
 		v -= floor(v);
-		return pixmap->get(u*pixmap->getWidth(), v*pixmap->getHeight());
+		return pixmap->get((int)(u*pixmap->getWidth()), (int)(v*pixmap->getHeight()));
 	};
 };
 
--- a/include/raytracer.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/raytracer.h	Thu Apr 24 13:55:11 2008 +0200
@@ -57,6 +57,7 @@
 	Float ao_distance, ao_angle;
 	int num_threads;
 	int max_depth;
+	bool use_packets;
 
 	Vector3 SphereDistribute(int i, int n, Float extent, Vector3 &normal);
 
@@ -66,10 +67,13 @@
 	pthread_mutex_t sample_queue_mutex, sampler_mutex;
 	pthread_cond_t sample_queue_cond, worker_ready_cond;
 
+	Colour shader_evalulate(Ray &ray, int depth, Shape *origin_shape,
+		Float nearest_distance, Shape *nearest_shape);
+	void raytracePacket(Ray *rays, Colour *results);
 	static void *raytrace_worker(void *d);
 public:
 	Raytracer(): top(NULL), camera(NULL), lights(), bg_colour(0., 0., 0.),
-		ao_samples(0), num_threads(2), max_depth(3)
+		ao_samples(0), num_threads(2), max_depth(3), use_packets(true)
 	{
 		pthread_mutex_init(&sample_queue_mutex, NULL);
 		pthread_mutex_init(&sampler_mutex, NULL);
--- a/include/sampler.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/sampler.h	Thu Apr 24 13:55:11 2008 +0200
@@ -55,17 +55,20 @@
  */
 class Sampler
 {
-public:
+protected:
 	Float *buffer;
 	int w,h;
-
-	Sampler(Float *abuffer, int &aw, int &ah): buffer(abuffer), w(aw), h(ah) {};
+	bool packetable;
+public:
+	Sampler(Float *abuffer, int &aw, int &ah):
+		buffer(abuffer), w(aw), h(ah), packetable(false) {};
 	virtual ~Sampler() {};
 	void resetBuffer(Float *abuffer, int &aw, int &ah) { buffer = abuffer; w = aw; h = ah; };
 	virtual void init() = 0;
 	virtual int initSampleSet() = 0;
 	virtual bool nextSample(Sample *s) = 0;
 	virtual void saveSample(Sample &samp, Colour &col) = 0;
+	bool packetableSamples() { return packetable; };
 };
 
 /**
@@ -80,7 +83,7 @@
 	int sx,sy,osa_samp; // current sample properties
 public:
 	DefaultSampler(Float *abuffer, int &aw, int &ah):
-		Sampler(abuffer, aw, ah), phase(-1), subsample(4), oversample(0) {};
+		Sampler(abuffer, aw, ah), phase(-1), subsample(0), oversample(0) {};
 	void init();
 	int initSampleSet();
 	bool nextSample(Sample *s);
--- a/include/scene.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/scene.h	Thu Apr 24 13:55:11 2008 +0200
@@ -77,6 +77,12 @@
 		dir.normalize();
 		return Ray(eye, dir);
 	};
+
+	void makeRayPacket(Sample *samples, Ray *rays)
+	{
+		for (int i = 0; i < 4; i++)
+			rays[i] = makeRay(samples[i]);
+	};
 };
 
 /**
--- a/include/shapes.h	Thu Apr 24 10:49:11 2008 +0200
+++ b/include/shapes.h	Thu Apr 24 13:55:11 2008 +0200
@@ -132,6 +132,7 @@
 public:
 	Vector3 P;
 	Vertex(const Vector3 &aP): P(aP) {};
+	virtual ~Vertex() {};
 	virtual ostream & dump(ostream &st) const;
 };
 
--- a/src/container.cc	Thu Apr 24 10:49:11 2008 +0200
+++ b/src/container.cc	Thu Apr 24 13:55:11 2008 +0200
@@ -60,6 +60,14 @@
 	return nearest_shape;
 }
 
+void Container::packet_intersection(const Shape **origin_shapes, const Ray *rays,
+	Float *nearest_distances, Shape **nearest_shapes)
+{
+	for (int i = 0; i < 4; i++)
+		nearest_shapes[i] = nearest_intersection(origin_shapes[i], rays[i],
+			nearest_distances[i]);
+}
+
 ostream & Container::dump(ostream &st)
 {
 	st << "(container," << shapes.size();
--- 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
--- a/src/sampler.cc	Thu Apr 24 10:49:11 2008 +0200
+++ b/src/sampler.cc	Thu Apr 24 13:55:11 2008 +0200
@@ -32,6 +32,7 @@
 void DefaultSampler::init()
 {
 	phase = 0;
+	packetable = (subsample <= 1);
 }
 
 int DefaultSampler::initSampleSet()