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