# HG changeset patch # User Radek Brich # Date 1209038111 -7200 # Node ID 930a2d3ecaed4b4b4f57995f649a6a96de19d470 # Parent 9dbb9c8c115bd91e2b11f982f41e5469c2eec480 prepare structures for packet tracing (it's already slightly faster, even without any explicit parallelization) supply missing virtual destructors diff -r 9dbb9c8c115b -r 930a2d3ecaed include/container.h --- 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; }; diff -r 9dbb9c8c115b -r 930a2d3ecaed include/material.h --- 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())); }; }; diff -r 9dbb9c8c115b -r 930a2d3ecaed include/raytracer.h --- 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); diff -r 9dbb9c8c115b -r 930a2d3ecaed include/sampler.h --- 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); diff -r 9dbb9c8c115b -r 930a2d3ecaed include/scene.h --- 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]); + }; }; /** diff -r 9dbb9c8c115b -r 930a2d3ecaed include/shapes.h --- 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; }; diff -r 9dbb9c8c115b -r 930a2d3ecaed src/container.cc --- 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(); diff -r 9dbb9c8c115b -r 930a2d3ecaed src/raytracer.cc --- 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 #include #include +#include #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::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::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 diff -r 9dbb9c8c115b -r 930a2d3ecaed src/sampler.cc --- 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()