pyrit_verbosity: new variable for controlling amount of output, see common.h
fix Makefile dependencies for raytracer_module
fix bad view in buddha.py caused by last commit
/* * C++ RayTracer * file: raytracer.cc * * Radek Brich, 2006 */#ifdef PTHREADS#include <pthread.h>#endif#include <stdio.h>#include <malloc.h>#include "raytracer.h"int pyrit_verbosity = 2;// Hammersley spherical point distribution// http://www.cse.cuhk.edu.hk/~ttwong/papers/udpoint/udpoints.htmlVector3 Raytracer::SphereDistribute(int i, int n, Float extent, Vector3 &normal){ Float p, t, st, phi, phirad; int kk; t = 0; for (p=0.5, kk=i; kk; p*=0.5, kk>>=1) if (kk & 1) t += p; t = 1.0 + (t - 1.0)*extent; phi = (i + 0.5) / n; phirad = phi * 2.0 * M_PI; st = sqrt(1.0 - t*t); Float x, y, z, xx, yy, zz, q; x = st * cos(phirad); y = st * sin(phirad); z = t; // rotate against Y axis q = acos(normal.z); zz = z*cos(q) - x*sin(q); xx = z*sin(q) + x*cos(q); yy = y; // rotate against Z axis q = atan2f(normal.y, normal.x); x = xx*cos(q) - yy*sin(q); y = xx*sin(q) + yy*cos(q); z = zz; return Vector3(x, y, z);}// ---- tyto dve funkce budou v budouci verzi metody objektu PhongShader// calculate shader function// P is point of intersection, N normal in this pointColour PhongShader_ambient(Material &mat, Vector3 &P){ Colour col = mat.texture.colour; //mat.texture.evaluate(P); // ambient return mat.ambient * col;}/* P is point of intersection, N normal in this point, R direction of reflected ray, V direction to the viewer*/Colour PhongShader_calculate(Material &mat, Vector3 &P, Vector3 &N, Vector3 &R, Vector3 &V, Light &light){ Colour I = Colour(); Vector3 L = light.pos - P; L.normalize(); Float L_dot_N = dot(L, N); Float R_dot_V = dot(R, V); Colour col = mat.texture.colour; //mat.texture.evaluate(P); // diffuse I = mat.diffuse * col * light.colour * L_dot_N; // specular if (R_dot_V > 0) I += mat.specular * light.colour * powf(R_dot_V, mat.shininess); return I;}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) { return bg_colour; } else { Colour acc = Colour(); Vector3 P = ray.o + ray.dir * nearest_distance; // point of intersection Vector3 normal = nearest_shape->normal(P); // make shapes double sided if (dot(normal, ray.dir) > 0.0) normal = - normal; acc = 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; acc += PhongShader_calculate(*nearest_shape->material, P, normal, R, ray.dir, **light); } } // reflection Vector3 newdir = ray.dir - 2.0 * dot(ray.dir, normal) * normal; if (depth < max_depth && nearest_shape->material->reflection > 0.01) { Ray newray = Ray(P, newdir); Colour refl_col = raytrace(newray, depth + 1, nearest_shape); acc += nearest_shape->material->reflection * refl_col; } // refraction /* ... */ // ambient occlusion if (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; acc = acc * ao_intensity; } return acc; }}static void *renderrow(void *data){ RenderrowData *d = (RenderrowData*) data; int subsample = d->rt->getSubsample(); Float subsample2 = 1.0/(subsample*subsample); int ww = d->w*3; Vector3 dir = d->dfix; for (int x = 0; x < d->w; x += subsample) { // generate a ray from eye passing through this pixel#if OVERSAMPLING // 5x oversampling Colour c = Colour(); for (int i = 0; i < 5; i++) { Float osax[] = {0.0, -0.4, +0.4, +0.4, -0.4}; Float osay[] = {0.0, -0.4, -0.4, +0.4, +0.4}; Vector3 tmpdir = dir + osax[i]*d->dx + osay[i]*d->dy; tmpdir.normalize(); Ray ray(d->eye, tmpdir); c += d->rt->raytrace(ray, 0, NULL); } c = c * (1./5);#else // no oversampling dir.normalize(); Ray ray(d->eye, dir); Colour c = d->rt->raytrace(ray, 0, NULL); if (subsample > 1) { Colour ic; // top-left is 'c' // top-right Vector3 tmpdir = dir + (subsample-1)*d->dx; tmpdir.normalize(); Ray ray(d->eye, tmpdir); Colour c2 = d->rt->raytrace(ray, 0, NULL); // bottom right tmpdir += (subsample-1)*d->dy; tmpdir.normalize(); ray.dir = tmpdir; Colour c4 = d->rt->raytrace(ray, 0, NULL); // bottom left tmpdir = dir + (subsample-1)*d->dy; tmpdir.normalize(); ray.dir = tmpdir; Colour c3 = d->rt->raytrace(ray, 0, NULL); // are the colors similar? Float m = (c-c2).mag2(); m = max(m, (c2-c3).mag2()); m = max(m, (c3-c4).mag2()); m = max(m, (c4-c).mag2()); if (m < 0.001) { // interpolate Float *i = d->iter; for (int x = 0; x < subsample; x++) { for (int y = 0; y < subsample; y++) { ic = c*(subsample-x)*(subsample-y)*subsample2 + c2*(x)*(subsample-y)*subsample2 + c3*(subsample-x)*(y)*subsample2 + c4*(x)*(y)*subsample2; *(i + ww*y) = ic.r; *(i + ww*y + 1) = ic.g; *(i + ww*y + 2) = ic.b; } i += 3; } d->iter = i; } else { // render Vector3 tmpdir = dir; // first column *(d->iter) = c.r; *(d->iter + 1) = c.g; *(d->iter + 2) = c.b; for (int y = 1; y < subsample-1; y++) { Vector3 tmp2dir = tmpdir + y*d->dy; tmp2dir.normalize(); ray.dir = tmp2dir; ic = d->rt->raytrace(ray, 0, NULL); *(d->iter + ww*y) = ic.r; *(d->iter + ww*y + 1) = ic.g; *(d->iter + ww*y + 2) = ic.b; } *(d->iter + ww*(subsample-1)) = c3.r; *(d->iter + ww*(subsample-1) + 1) = c3.g; *(d->iter + ww*(subsample-1) + 2) = c3.b; d->iter += 3; tmpdir += d->dx; // middle for (int x = 1; x < subsample-1; x++) { for (int y = 0; y < subsample; y++) { Vector3 tmp2dir = tmpdir + y*d->dy; tmp2dir.normalize(); ray.dir = tmp2dir; ic = d->rt->raytrace(ray, 0, NULL); *(d->iter + ww*y) = ic.r; *(d->iter + ww*y + 1) = ic.g; *(d->iter + ww*y + 2) = ic.b; } d->iter += 3; tmpdir += d->dx; } // last column *(d->iter) = c2.r; *(d->iter + 1) = c2.g; *(d->iter + 2) = c2.b; for (int y = 1; y < subsample-1; y++) { Vector3 tmp2dir = tmpdir + y*d->dy; tmp2dir.normalize(); ray.dir = tmp2dir; ic = d->rt->raytrace(ray, 0, NULL); *(d->iter + ww*y) = ic.r; *(d->iter + ww*y + 1) = ic.g; *(d->iter + ww*y + 2) = ic.b; } *(d->iter + ww*(subsample-1)) = c4.r; *(d->iter + ww*(subsample-1) + 1) = c4.g; *(d->iter + ww*(subsample-1) + 2) = c4.b; d->iter += 3; } }#endif if (subsample <= 1) { *d->iter++ = c.r; *d->iter++ = c.g; *d->iter++ = c.b; } dir += d->dx*subsample; }#ifdef PTHREADS pthread_exit((void *)d);#endif return (void *)d;}void Raytracer::render(int w, int h, Float *buffer){ if (!camera || !top || !buffer) return; RenderrowData *d; Float S = 0.5/w; Vector3 dfix = camera->u*(-w/2.0*S/camera->f) + camera->v*(h/2.0*S/camera->f) + camera->p; Vector3 dx = camera->u * (S/camera->f); Vector3 dy = camera->v * (-S/camera->f);#ifdef PTHREADS dbgmsg(1, "* pthreads enabled, using %d threads\n", num_threads); pthread_t threads[num_threads]; for (int t = 0; t < num_threads; t++) threads[t] = pthread_self(); int t = 0;#endif /* for each pixel... */ dbgmsg(1, "* raytracing...\n"); dbgmsg(2, "- row 0 ( 0%% done)"); for (int y = 0; y < h; y += subsample) { d = (RenderrowData*) malloc(sizeof(RenderrowData)); d->rt = this; d->w = w; d->eye = camera->eye; d->dfix = dfix; d->dx = dx; d->dy = dy; d->iter = buffer + y*3*w;#ifdef PTHREADS /* create new thread and increase 't' */ int rc = pthread_create(&threads[t++], NULL, renderrow, (void *)d); if (rc) { dbgmsg(0, "\nE pthread_create unsuccessful, return code was %d\n", rc); exit(1); } /* when 't' owerflows, reset it */ if (t >= num_threads) t = 0; /* wait for next thread in fifo queue, so the descriptor can be reused; this also limits number of running threads */ if (!pthread_equal(threads[t], pthread_self())) if (pthread_join(threads[t], (void**)&d) == 0) free(d);#else renderrow((void *)d); free(d);#endif dfix += dy*subsample; dbgmsg(2, "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%4d (%2d%% done)", y, y*100/(h-1)); } dbgmsg(2, "\n");#ifdef PTHREADS dbgmsg(2, "- waiting for threads to finish\n"); for (t = 0; t < num_threads; t++) if (pthread_join(threads[t], (void**)&d) == 0) free(d);#endif}void Raytracer::addlight(Light *light){ lights.push_back(light);}void Raytracer::ambientocclusion(int samples, Float distance, Float angle){ ao_samples = samples; ao_distance = distance; ao_angle = angle; if (ao_distance == 0) /* 0 ==> Inf */ ao_distance = FLT_MAX;}