comparison demos/ray.d @ 94:61615fa85940 trunk

[svn r98] Added support for std.c.stdlib.alloca via pragma(LLVM_internal, "alloca"). Added support for array .sort and .reverse properties. Fixed some bugs with pointer arithmetic. Disabled some DMD AST optimizations that was messing things up, destroying valuable information. Added a KDevelop project file, this is what I use for coding LLVMDC now :) Other minor stuff.
author lindquist
date Mon, 12 Nov 2007 06:32:46 +0100
parents
children
comparison
equal deleted inserted replaced
93:08508eebbb3e 94:61615fa85940
1 //import std.stdio, std.math, std.string;
2 //import tools.base;
3
4 double delta;
5 static this() { delta=sqrt(real.epsilon); }
6
7 struct Vec {
8 double x, y, z;
9 Vec opAdd(ref Vec other) { return Vec(x+other.x, y+other.y, z+other.z); }
10 Vec opSub(ref Vec other) { return Vec(x-other.x, y-other.y, z-other.z); }
11 Vec opMul(double a) { return Vec(x*a, y*a, z*a); }
12 double dot(ref Vec other) { return x*other.x+y*other.y+z*other.z; }
13 Vec unitise() { return opMul(1.0/sqrt(dot(*this))); }
14 }
15
16 struct Pair(T, U) { T first; U second; }
17 typedef Pair!(double, Vec) Hit;
18
19 struct Ray { Vec orig, dir; }
20
21 class Scene {
22 abstract void intersect(ref Hit, ref Ray);
23 }
24
25 class Sphere : Scene {
26 Vec center;
27 double radius;
28 this(ref Vec c, double r)
29 {
30 center = c;
31 radius = r;
32 }
33 double ray_sphere(ref Ray ray) {
34 auto v = center - ray.orig, b = v.dot(ray.dir), disc=b*b - v.dot(v) + radius*radius;
35 if (disc < 0) return double.infinity;
36 auto d = sqrt(disc), t2 = b + d;
37 if (t2 < 0) return double.infinity;
38 auto t1 = b - d;
39 return (t1 > 0 ? t1 : t2);
40 }
41 void intersect(ref Hit hit, ref Ray ray) {
42 auto lambda = ray_sphere(ray);
43 if (lambda < hit.first)
44 hit = Hit(lambda, (ray.orig + lambda*ray.dir - center).unitise);
45 }
46 }
47
48 class Group : Scene {
49 Sphere bound;
50 Scene[] children;
51 mixin This!("bound, children");
52 void intersect(ref Hit hit, ref Ray ray) {
53 auto l = bound.ray_sphere(ray);
54 if (l < hit.first) foreach (child; children) child.intersect(hit, ray);
55 }
56 }
57
58 double ray_trace(ref Vec light, ref Ray ray, Scene s) {
59 auto hit=Hit(double.infinity, Vec(0, 0, 0));
60 s.intersect(hit, ray);
61 if (hit.first == double.infinity) return 0.0;
62 auto g = hit.second.dot(light);
63 if (g >= 0) return 0.0;
64 auto p = ray.orig + ray.dir*hit.first + hit.second*delta;
65 auto hit2=Hit(double.infinity, Vec(0, 0, 0));
66 s.intersect(hit2, Ray(p, light*-1.0));
67 return (hit2.first < double.infinity ? 0 : -g);
68 }
69
70 Scene create(int level, ref Vec c, double r) {
71 auto s = new Sphere(c, r);
72 if (level == 1) return s;
73 Scene[] children=[s];
74 double rn = 3*r/sqrt(12.0);
75 for (int dz=-1; dz<=1; dz+=2)
76 for (int dx=-1; dx<=1; dx+=2)
77 children~=create(level-1, c + Vec(dx, 1, dz)*rn, r/2);
78 return new Group(new Sphere(c, 3*r), children);
79 }
80
81 void main(string[] args) {
82 int level = (args.length==3 ? args[1].atoi() : 9),
83 n = (args.length==3 ? args[2].atoi() : 512), ss = 4;
84 auto light = Vec(-1, -3, 2).unitise();
85 auto s=create(level, Vec(0, -1, 0), 1);
86 writefln("P5\n", n, " ", n, "\n255");
87 for (int y=n-1; y>=0; --y)
88 for (int x=0; x<n; ++x) {
89 double g=0;
90 for (int d=0; d<ss*ss; ++d) {
91 auto dir=Vec(x+(d%ss)*1.0/ss-n/2.0, y+(d/ss)*1.0/ss-n/2.0, n).unitise();
92 g += ray_trace(light, Ray(Vec(0, 0, -4), dir), s);
93 }
94 printf("%c", cast(ubyte)(0.5 + 255.0 * g / (ss*ss)));
95 }
96 }