Mercurial > projects > ldc
comparison demos/ray.cpp @ 180:90522b72128a trunk
[svn r196] Added C++ version of the ray demo for comparing.
author | lindquist |
---|---|
date | Wed, 07 May 2008 18:46:56 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
179:c853a8a04cdc | 180:90522b72128a |
---|---|
1 #include <list> | |
2 #include <iostream> | |
3 #include <limits> | |
4 #include <cmath> | |
5 #include <cstdlib> | |
6 | |
7 using namespace std; | |
8 | |
9 numeric_limits<double> real; | |
10 double delta = sqrt(real.epsilon()), infinity = real.infinity(); | |
11 | |
12 struct Vec { | |
13 double x, y, z; | |
14 Vec(double x2, double y2, double z2) : x(x2), y(y2), z(z2) {} | |
15 }; | |
16 Vec operator+(const Vec &a, const Vec &b) | |
17 { return Vec(a.x+b.x, a.y+b.y, a.z+b.z); } | |
18 Vec operator-(const Vec &a, const Vec &b) | |
19 { return Vec(a.x-b.x, a.y-b.y, a.z-b.z); } | |
20 Vec operator*(double a, const Vec &b) { return Vec(a*b.x, a*b.y, a*b.z); } | |
21 double dot(const Vec &a, const Vec &b) { return a.x*b.x + a.y*b.y + a.z*b.z; } | |
22 Vec unitise(const Vec &a) { return (1 / sqrt(dot(a, a))) * a; } | |
23 | |
24 typedef pair<double, Vec> Hit; | |
25 | |
26 struct Ray { | |
27 Vec orig, dir; | |
28 Ray(const Vec &o, const Vec &d) : orig(o), dir(d) {} | |
29 }; | |
30 | |
31 struct Scene { | |
32 virtual ~Scene() {}; | |
33 virtual void intersect(Hit &, const Ray &) const = 0; | |
34 }; | |
35 | |
36 struct Sphere : public Scene { | |
37 Vec center; | |
38 double radius; | |
39 | |
40 Sphere(Vec c, double r) : center(c), radius(r) {} | |
41 ~Sphere() {} | |
42 | |
43 double ray_sphere(const Ray &ray) const { | |
44 Vec v = center - ray.orig; | |
45 double b = dot(v, ray.dir), disc = b*b - dot(v, v) + radius * radius; | |
46 if (disc < 0) return infinity; | |
47 double d = sqrt(disc), t2 = b + d; | |
48 if (t2 < 0) return infinity; | |
49 double t1 = b - d; | |
50 return (t1 > 0 ? t1 : t2); | |
51 } | |
52 | |
53 void intersect(Hit &hit, const Ray &ray) const { | |
54 double lambda = ray_sphere(ray); | |
55 if (lambda >= hit.first) return; | |
56 hit = Hit(lambda, unitise(ray.orig + lambda*ray.dir - center)); | |
57 } | |
58 }; | |
59 | |
60 typedef list<Scene *> Scenes; | |
61 struct Group : public Scene { | |
62 Sphere bound; | |
63 Scenes child; | |
64 | |
65 Group(Sphere b, Scenes c) : bound(b), child(c) {} | |
66 ~Group() { | |
67 for (Scenes::const_iterator it=child.begin(); it!=child.end(); ++it) | |
68 delete *it; | |
69 } | |
70 | |
71 void intersect(Hit &hit, const Ray &ray) const { | |
72 double l = bound.ray_sphere(ray); | |
73 if (l < hit.first) | |
74 for (Scenes::const_iterator it=child.begin(); it!=child.end(); ++it) | |
75 (*it)->intersect(hit, ray); | |
76 } | |
77 }; | |
78 | |
79 Hit intersect(const Ray &ray, const Scene &s) { | |
80 Hit res = Hit(infinity, Vec(0, 0, 0)); | |
81 s.intersect(res, ray); | |
82 return res; | |
83 } | |
84 | |
85 double ray_trace(const Vec &light, const Ray &ray, const Scene &s) { | |
86 Hit hit = intersect(ray, s); | |
87 if (hit.first == infinity) return 0; | |
88 double g = dot(hit.second, light); | |
89 if (g >= 0) return 0.; | |
90 Vec p = ray.orig + hit.first*ray.dir + delta*hit.second; | |
91 return (intersect(Ray(p, -1. * light), s).first < infinity ? 0 : -g); | |
92 } | |
93 | |
94 Scene *create(int level, const Vec &c, double r) { | |
95 Scene *s = new Sphere(c, r); | |
96 if (level == 1) return s; | |
97 Scenes child; | |
98 child.push_back(s); | |
99 double rn = 3*r/sqrt(12.); | |
100 for (int dz=-1; dz<=1; dz+=2) | |
101 for (int dx=-1; dx<=1; dx+=2) | |
102 child.push_back(create(level-1, c + rn*Vec(dx, 1, dz), r/2)); | |
103 return new Group(Sphere(c, 3*r), child); | |
104 } | |
105 | |
106 int main(int argc, char *argv[]) { | |
107 int level = 6, n = 512, ss = 4; | |
108 if (argc == 2) level = atoi(argv[1]); | |
109 Vec light = unitise(Vec(-1, -3, 2)); | |
110 Scene *s(create(level, Vec(0, -1, 0), 1)); | |
111 cout << "P5\n" << n << " " << n << "\n255\n"; | |
112 for (int y=n-1; y>=0; --y) | |
113 for (int x=0; x<n; ++x) { | |
114 double g=0; | |
115 for (int dx=0; dx<ss; ++dx) | |
116 for (int dy=0; dy<ss; ++dy) { | |
117 Vec dir(unitise(Vec(x+dx*1./ss-n/2., y+dy*1./ss-n/2., n))); | |
118 g += ray_trace(light, Ray(Vec(0, 0, -4), dir), *s); | |
119 } | |
120 cout << char(int(.5 + 255. * g / (ss*ss))); | |
121 } | |
122 delete s; | |
123 return 0; | |
124 } |