prepare structures for packet tracing
(it's already slightly faster, even without any explicit parallelization)
supply missing virtual destructors
--- 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()