new C++ demo: realtime.cc (real-time scene viewer using SDL)
Quaternion, Camera::rotate and Camera::move
replace all printf's with infomsg wrapper
don't allocate memory in Raytracer::render, just blindly write to provided address
don't creat Container object in Raytracer, let user do it
/* * C++ RayTracer * file: scene.cc * * Radek Brich, 2006 */#include <math.h>#include "common.h"#include "scene.h"void Camera::rotate(const Quaternion &q){ Quaternion res; res = q * Quaternion(u) * conjugate(q); u = res.toVector(); res = q * Quaternion(v) * conjugate(q); v = res.toVector(); res = q * Quaternion(p) * conjugate(q); p = res.toVector(); p.normalize(); u.normalize(); v.normalize();/* // optimized version float t2 = q.a*q.b; float t3 = q.a*q.c; float t4 = q.a*q.d; float t5 = -q.b*q.b; float t6 = q.b*q.c; float t7 = q.b*q.d; float t8 = -q.c*q.c; float t9 = q.c*q.d; float t10 = -q.d*q.d; float x,y,z; x = 2*( (t8 + t10)*p.x + (t6 - t4)*p.y + (t3 + t7)*p.z ) + p.x; y = 2*( (t4 + t6)*p.x + (t5 + t10)*p.y + (t9 - t2)*p.z ) + p.y; z = 2*( (t7 - t3)*p.x + (t2 + t9)*p.y + (t5 + t8)*p.z ) + p.z; p = Vector3(x,y,z); x = 2*( (t8 + t10)*u.x + (t6 - t4)*u.y + (t3 + t7)*u.z ) + u.x; y = 2*( (t4 + t6)*u.x + (t5 + t10)*u.y + (t9 - t2)*u.z ) + u.y; z = 2*( (t7 - t3)*u.x + (t2 + t9)*u.y + (t5 + t8)*u.z ) + u.z; u = Vector3(x,y,z); x = 2*( (t8 + t10)*v.x + (t6 - t4)*v.y + (t3 + t7)*v.z ) + v.x; y = 2*( (t4 + t6)*v.x + (t5 + t10)*v.y + (t9 - t2)*v.z ) + v.y; z = 2*( (t7 - t3)*v.x + (t2 + t9)*v.y + (t5 + t8)*v.z ) + v.z; v = Vector3(x,y,z);*/}void Camera::move(const float fw, const float left, const float up){ eye = eye + fw*p + left*u + up*v;}/* http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm */bool BBox::intersect(const Ray &ray, float &a, float &b){ float tnear = -FLT_MAX; float tfar = FLT_MAX; float t1, t2; for (int i = 0; i < 3; i++) { if (ray.dir.cell[i] == 0) { /* ray is parallel to these planes */ if (ray.o.cell[i] < L.cell[i] || ray.o.cell[i] > H.cell[i]) return false; } else { /* compute the intersection distance of the planes */ t1 = (L.cell[i] - ray.o.cell[i]) / ray.dir.cell[i]; t2 = (H.cell[i] - ray.o.cell[i]) / ray.dir.cell[i]; if (t1 > t2) swap(t1, t2); if (t1 > tnear) tnear = t1; /* want largest Tnear */ if (t2 < tfar) tfar = t2; /* want smallest Tfar */ if (tnear > tfar) return false; /* box missed */ if (tfar < 0) return false; /* box is behind ray */ } } a = tnear; b = tfar; return true;}bool Sphere::intersect(const Ray &ray, float &dist){ Vector3 V = ((Ray)ray).o - center; float Vd = - dot(V, ray.dir); float Det = Vd * Vd - (dot(V,V) - sqr_radius); if (Det > 0) { Det = sqrtf(Det); float t1 = Vd - Det; if (t1 > 0) { if (t1 < dist) { dist = t1; return true; } } else { float t2 = Vd + Det; if (t2 > 0) { // ray from inside of the sphere dist = t2; return true; } } } return false;}bool Sphere::intersect_all(const Ray &ray, float dist, vector<float> &allts){ //allts = new vector<float>(); Vector3 V = ((Ray)ray).o - center; float Vd = - dot(V, ray.dir); float Det = Vd * Vd - (dot(V,V) - sqr_radius); if (Det > 0) { Det = sqrtf(Det); float t1 = Vd - Det; float t2 = Vd + Det; if (t1 < 0) { if (t2 > 0) { // ray from inside of the sphere allts.push_back(0.0); allts.push_back(t2); return true; } else return false; } else { allts.push_back(t1); allts.push_back(t2); return true; } } return false;}BBox Sphere::get_bbox(){ BBox bbox = BBox(); bbox.L = center - radius; bbox.H = center + radius; return bbox;}bool Box::intersect(const Ray &ray, float &dist){ float b; return get_bbox().intersect(ray, dist, b);}Vector3 Box::normal(Vector3 &P){ Vector3 N; for (int i = 0; i < 3; i++) { if (P.cell[i] >= L.cell[i]-Eps && P.cell[i] <= L.cell[i]+Eps) //if (P.cell[i] == L.cell[i]) { N.cell[i] = -1.0; break; } if (P.cell[i] >= H.cell[i]-Eps && P.cell[i] <= H.cell[i]+Eps) //if (P.cell[i] == H.cell[i]) { N.cell[i] = +1.0; break; } } return N;}// this initialization and following intersection methods implements// Fast Triangle Intersection algorithm from// http://www.mpi-inf.mpg.de/~wald/PhD/Triangle::Triangle(const Vector3 &aA, const Vector3 &aB, const Vector3 &aC, Material *amaterial) : A(aA), B(aB), C(aC){ material = amaterial; Vector3 c = B - A; Vector3 b = C - A; N = cross(c, b); if (fabsf(N.x) > fabsf(N.y)) { if (fabsf(N.x) > fabsf(N.z)) k = 0; else k = 2; } else { if (fabsf(N.y) > fabsf(N.z)) k = 1; else k = 2; } int u = (k + 1) % 3; int v = (k + 2) % 3; float krec = 1.0f / N[k]; nu = N[u] * krec; nv = N[v] * krec; nd = dot(N, A) * krec; // first line equation float reci = 1.0f / (b[u] * c[v] - b[v] * c[u]); bnu = b[u] * reci; bnv = -b[v] * reci; // second line equation cnu = c[v] * reci; cnv = -c[u] * reci; // finalize normal N.normalize();}// see comment for previous methodbool Triangle::intersect(const Ray &ray, float &dist){ Vector3 O = ray.o; Vector3 D = ray.dir; const int modulo3[5] = {0,1,2,0,1}; const int ku = modulo3[k+1]; const int kv = modulo3[k+2]; const float lnd = 1.0f / (D[k] + nu * D[ku] + nv * D[kv]); const float t = (nd - O[k] - nu * O[ku] - nv * O[kv]) * lnd; if (!(t < dist && t > 0)) return false; float hu = O[ku] + t * D[ku] - A[ku]; float hv = O[kv] + t * D[kv] - A[kv]; float beta = hv * bnu + hu * bnv; if (beta < 0) return false; float gamma = hu * cnu + hv * cnv; if (gamma < 0) return false; if ((beta + gamma) > 1) return false; dist = t; return true;}BBox Triangle::get_bbox(){ BBox bbox = BBox(); bbox.L = A; if (B.x < bbox.L.x) bbox.L.x = B.x; if (C.x < bbox.L.x) bbox.L.x = C.x; if (B.y < bbox.L.y) bbox.L.y = B.y; if (C.y < bbox.L.y) bbox.L.y = C.y; if (B.z < bbox.L.z) bbox.L.z = B.z; if (C.z < bbox.L.z) bbox.L.z = C.z; bbox.H = A; if (B.x > bbox.H.x) bbox.H.x = B.x; if (C.x > bbox.H.x) bbox.H.x = C.x; if (B.y > bbox.H.y) bbox.H.y = B.y; if (C.y > bbox.H.y) bbox.H.y = C.y; if (B.z > bbox.H.z) bbox.H.z = B.z; if (C.z > bbox.H.z) bbox.H.z = C.z; return bbox;};