D Paste by flithm
Description: None
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | module tracetest; import tango.math.Math; import tango.core.Memory; import tango.stdc.stdio; import tango.stdc.string; const double delta; static this() { delta=sqrt(double.epsilon); } struct Vec { double x, y, z; static void add(ref Vec a, ref Vec b, ref Vec ret) {ret.x = a.x+b.x; ret.y = a.y+b.y; ret.z = a.z+b.z;} static void sub(ref Vec a, ref Vec b, ref Vec ret) {ret.x = a.x-b.x; ret.y = a.y-b.y; ret.z = a.z-b.z;} static void mul(ref Vec a, double b, ref Vec ret) {ret.x = a.x*b; ret.y = a.y*b; ret.z = a.z*b;} double dot(ref Vec b) { return x*b.x + y*b.y + z*b.z; } static void unitise(ref Vec a, ref Vec ret) { mul(a, 1f / sqrt(a.dot(a)), ret); return ret; } } struct Hit { double dist; Vec pos; } struct Ray { Vec orig, dir; } class Scene { abstract void intersect(ref Hit hit, ref Ray ray); } template StdConstructor() { this(typeof(this.tupleof) p) { foreach (index, bogus; this.tupleof) this.tupleof[index]=p[index]; } } final class Sphere : Scene { Vec center; double radius; mixin StdConstructor; double ray_sphere(ref Ray ray) { Vec v = void; Vec.sub(center, ray.orig, v); double b = v.dot(ray.dir), disc = b*b - v.dot(v) + radius * radius; if (disc < 0) return double.infinity; double d = sqrt(disc), t2 = b + d; if (t2 < 0) return double.infinity; auto t1 = b - d; return t1 > 0 ? t1 : t2; } void intersect(ref Hit hit, ref Ray ray) { auto lambda = ray_sphere(ray); if (lambda >= hit.dist) return; Vec v = void; Vec mulVec = void; Vec.mul(ray.dir, lambda, mulVec); Vec.add(ray.orig, mulVec, v); Vec.sub(v, center, v); Vec.unitise(v, v); hit.dist = lambda; hit.pos = v; } } final class Group : Scene { Sphere bound; Scene[] child; mixin StdConstructor; void intersect(ref Hit hit, ref Ray ray) { double l = bound.ray_sphere(ray); if (l < hit.dist) for (int i=0; i<child.length; ++i) child[i].intersect(hit, ray); } } void intersect(ref Ray ray, Scene s, ref Hit res) { res.dist = double.infinity; memset(cast(void *) &res.pos, 0, Vec.sizeof); s.intersect(res, ray); } double ray_trace(ref Vec light, ref Ray ray, Scene s) { Hit hit = void; intersect(ray, s, hit); if (hit.dist == double.infinity) return 0; auto g = hit.pos.dot(light); if (g >= 0) return 0.; Vec mulVec = void; Vec.mul(hit.pos, delta, mulVec); Vec mulVec1 = void; Vec.mul(ray.dir, hit.dist, mulVec1); Vec p = void; Vec.add(ray.orig, mulVec1, p); Vec.add(p, mulVec, p); Vec mulVec2 = void; Vec.mul(light, -1.0, mulVec2); Ray r = void; r.orig = p; r.dir = mulVec2; intersect(r, s, hit); return (hit.dist < double.infinity) ? 0 : -g; } Scene create(int level, ref Vec c, double r) { auto s = new Sphere(c, r); if (level == 1) return s; Scene[] child; child~=s; //child.length=1; child[0]=s; auto rn = 3f*r/sqrt(12f); for (auto dz=-1; dz<=1; dz+=2) for (auto dx=-1; dx<=1; dx+=2) { Vec mulVec = void; Vec.mul(Vec(dx, 1, dz), rn * rn, mulVec); Vec v = void; Vec.add(c, mulVec, v); child~=create(level-1, v, r/2f); } return new Group(new Sphere(c, 3*r), child); } int main(/*string[] args*/) { GC.disable(); int level = 6, n = 512, ss = 4; //if (args.length == 2) level = atoi(args[1]); auto light = Vec(-1, -3, 2); Vec.unitise(light, light); auto s=create(level, Vec(0, -1, 0), 1); printf("P5\n%i %i\n255\n", n, n); const Vec rVec = Vec(0, 0, -4); for (int y=n-1; y>=0; --y) for (int x=0; x<n; ++x) { double g=0; for (int dx=0; dx<ss; ++dx) for (int dy=0; dy<ss; ++dy) { Vec dir= void; dir.x = x+dx*1./ss-n/2.; dir.y = y+dy*1./ss-n/2.; dir.z = n; Vec.unitise(dir, dir); Ray r = void; r.orig = rVec; r.dir = dir; g += ray_trace(light, r, s); } if (g!=g) g=0f; printf("%d", .5 + 255.0 * g / (ss*ss)); } return 0; } |