D Paste by downs
Description: tracetest.d
|
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 | module tracetest; import std.math, std.string: atoi; import std.c.stdio: printf; import std.gc: malloc; const double delta; static this() { delta=sqrt(double.epsilon); } struct Vec { double x, y, z; Vec opAdd(ref Vec b) { return Vec(x+b.x, y+b.y, z+b.z); } Vec opSub(ref Vec b) { return Vec(x-b.x, y-b.y, z-b.z); } Vec opMul(double a) { return Vec(x*a, y*a, z*a); } double dot(ref Vec b) { return x*b.x + y*b.y + z*b.z; } Vec unitise() { return opMul(1f / sqrt(dot(*this))); } static Vec opCall(double a, double b, double c) { Vec res=void; res.x=a; res.y=b; res.z=c; return res; } } 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) { auto v = center - ray.orig; 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; hit = Hit(lambda, (ray.orig + lambda*ray.dir - center).unitise); } } 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); } } Hit intersect(ref Ray ray, Scene s) { auto res = Hit(double.infinity, Vec(0, 0, 0)); s.intersect(res, ray); return res; } double ray_trace(ref Vec light, ref Ray ray, Scene s) { auto hit = intersect(ray, s); if (hit.dist == double.infinity) return 0; auto g = hit.pos.dot(light); if (g >= 0) return 0.; auto p = ray.orig + ray.dir*hit.dist + hit.pos*delta; return (intersect(Ray(p, -1. * light), s).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) child~=create(level-1, c + rn*Vec(dx, 1, dz), r/2f); return new Group(new Sphere(c, 3*r), child); } int main(/*string[] args*/) { int level = 6, n = 512, ss = 4; //if (args.length == 2) level = atoi(args[1]); auto light = Vec(-1, -3, 2).unitise; auto s=create(level, Vec(0, -1, 0), 1); printf("P5\n%i %i\n255\n", n, n); 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) { auto dir=Vec(x+dx*1./ss-n/2., y+dy*1./ss-n/2., n).unitise; g += ray_trace(light, Ray(Vec(0, 0, -4), dir), s); } if (g!=g) g=0f; printf("%c", cast(char)(.5f + 255f * g / (ss*ss))); } return 0; } |