--- 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