[svn] r5972: nemerle/trunk/snippets/raytracer: . ray-hand-opt.n
ray.cs
malekith
svnadmin at nemerle.org
Sun Nov 27 18:37:32 CET 2005
Log:
A hand-optimized version, and another translated from C#.
Author: malekith
Date: Sun Nov 27 18:37:31 2005
New Revision: 5972
Added:
nemerle/trunk/snippets/raytracer/ray-hand-opt.n
nemerle/trunk/snippets/raytracer/ray.cs
Modified:
nemerle/trunk/snippets/raytracer/ (props changed)
Added: nemerle/trunk/snippets/raytracer/ray-hand-opt.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/snippets/raytracer/ray-hand-opt.n Sun Nov 27 18:37:31 2005
@@ -0,0 +1,102 @@
+// based on http://www.ffconsultancy.com/free/ray_tracer/code/1/ray.ml
+#pragma indent
+using System.Math
+
+[Record] \
+struct Vec
+ x : double
+ y : double
+ z : double
+
+ public static @* (s : double, r : Vec) : Vec
+ Vec (s * r.x, s * r.y, s * r.z)
+ public static @+ (s : Vec, r : Vec) : Vec
+ Vec (s.x + r.x, s.y + r.y, s.z + r.z)
+ public static @- (s : Vec, r : Vec) : Vec
+ Vec (s.x - r.x, s.y - r.y, s.z - r.z)
+ public static @** (s : Vec, r : Vec) : double
+ s.x * r.x + s.y * r.y + s.z * r.z
+
+ public Unitise () : Vec
+ (1 / Sqrt (this ** this)) * this
+
+
+variant Scene
+ | Sphere { m : Vec; r : double; }
+ | Group { m : Vec; s : double; l : list [Scene]; }
+
+module M
+ delta = 1.49011611938476562e-08
+ inf : double = 1.0 / 0.0
+
+
+ ray_sphere (orig : Vec, dir : Vec, center : Vec, radius : double) : double
+ def v = center - orig
+ def b = v ** dir
+ def disc = b * b - (v ** v) + radius * radius
+ if (disc < 0) inf
+ else
+ def disc = Sqrt (disc)
+ def t2 = b + disc
+ def t1 = b - disc
+ if (t2 < 0) inf
+ else if (t1 > 0) t1
+ else t2
+
+ intersect (orig : Vec, dir : Vec, scene : Scene, first : double * Vec) : double * Vec
+ def l = first [0]
+ match (scene)
+ | Scene.Sphere (center, radius) =>
+ def l' = ray_sphere (orig, dir, center, radius)
+ if (l' >= l) first
+ else (l', (orig + l' * dir - center).Unitise ())
+ | Scene.Group (center, radius, scenes) =>
+ def l' = ray_sphere (orig, dir, center, radius)
+ if (l' >= l) first
+ else
+ mutable acc = first
+ foreach (s in scenes)
+ acc = intersect (orig, dir, s, acc)
+ acc
+
+ ray_trace (light:Vec, orig:Vec, dir:Vec, scene:Scene) : double
+ def (lambda, normal) = intersect (orig, dir, scene, (inf, Vec()))
+ if (lambda == inf) 0.0
+ else
+ def g = normal ** light
+ if (g >= 0) 0.0
+ else
+ def p = orig + lambda * dir + delta * normal
+ if ((intersect (p, -1 * light, scene, (inf,Vec()))) [0] < inf) 0.0
+ else -g
+
+ internal main (level : int, n : int) : void
+ def create (level, c, r)
+ def obj = Scene.Sphere (c, r)
+ if (level == 1) obj
+ else
+ def a = 3 * r / Sqrt (12)
+ def aux (x', z')
+ create (level - 1, c + Vec (x', a, z'), 0.5 * r)
+ Scene.Group (c, 3 * r , [obj, aux (-a, -a), aux (a, -a), aux (-a, a), aux (a, a)])
+
+ def scene = create (level, Vec (0, -1, 0), 1)
+ def light = Vec (-1, -3, 2).Unitise ()
+ def ss = 4
+ System.Console.Write ($ "P5\n$n $n\n255\n")
+ def s = System.Console.OpenStandardOutput ()
+ for (mutable y = n - 1; y >= 0; y--)
+ for (mutable x = 0; x < n; x++)
+ mutable g = 0.0
+ for (mutable dx = 0; dx < ss; dx++)
+ for (mutable dy = 0; dy < ss; dy++)
+ def aux (x, d)
+ x - n / 2.0 + d / (ss :> double)
+ def dir = Vec (aux (x, dx), aux (y, dy), n).Unitise ()
+ g += ray_trace (light, Vec (0,0,-4), dir, scene)
+ def res = (0.5 + 255 * g / (ss*ss)) :> int
+ s.WriteByte (res :> byte)
+
+match (Nemerle.Collections.List.FromArray (System.Environment.GetCommandLineArgs()))
+ | [_, level, n] => M.main (int.Parse (level), int.Parse (n))
+ | _ => M.main (9, 512)
Added: nemerle/trunk/snippets/raytracer/ray.cs
==============================================================================
--- (empty file)
+++ nemerle/trunk/snippets/raytracer/ray.cs Sun Nov 27 18:37:31 2005
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+
+class ray {
+ static double delta=1.49011611938476562e-08, infinity=double.PositiveInfinity;
+ struct Vec {
+ public double x, y, z;
+ public Vec(double x2, double y2, double z2) { x=x2; y=y2; z=z2; }
+ }
+
+ static Vec add(Vec a, Vec b) { return new Vec(a.x+b.x, a.y+b.y, a.z+b.z); }
+ static Vec sub(Vec a, Vec b) { return new Vec(a.x-b.x, a.y-b.y, a.z-b.z); }
+ static Vec scale(double s, Vec a) { return new Vec(s*a.x, s*a.y, s*a.z); }
+ static double dot(Vec a, Vec b) { return a.x*b.x + a.y*b.y + a.z*b.z; }
+ static Vec unitise(Vec a) { return scale(1 / Math.Sqrt(dot(a, a)), a); }
+
+ class Ray {
+ public Vec orig, dir;
+ public Ray(Vec o, Vec d) { orig=o; dir=d; }
+ }
+
+ class Hit {
+ public double lambda;
+ public Vec normal;
+ public Hit(double l, Vec n) { lambda=l; normal=n; }
+ }
+
+ abstract class Scene {
+ abstract public Hit intersect(Hit i, Ray ray);
+ }
+
+ class Sphere : Scene {
+ public Vec center;
+ public double radius;
+ public Sphere(Vec c, double r) { center=c; radius=r; }
+ public double ray_sphere(Ray ray) {
+ Vec v = sub(center, ray.orig);
+ double b = dot(v, ray.dir),
+ disc = b*b - dot(v, v) + radius*radius;
+ if (disc < 0) return infinity;
+ double d = Math.Sqrt(disc), t2 = b+d;
+ if (t2 < 0) return infinity;
+ double t1 = b-d;
+ return (t1 > 0 ? t1 : t2);
+ }
+ public override Hit intersect(Hit i, Ray ray) {
+ double l = ray_sphere(ray);
+ if (l >= i.lambda) return i;
+ Vec n = add(ray.orig, sub(scale(l, ray.dir), center));
+ return new Hit(l, unitise(n));
+ }
+ }
+
+ class Group : Scene {
+ public Sphere bound;
+ public List<Scene> objs;
+ public Group(Sphere b) {
+ bound = b;
+ objs = new List<Scene>();
+ }
+ public override Hit intersect(Hit i, Ray ray) {
+ double l = bound.ray_sphere(ray);
+ if (l >= i.lambda) return i;
+ foreach (Scene scene in objs) {
+ i = scene.intersect(i, ray);
+ }
+ return i;
+ }
+ }
+
+ static double ray_trace(Vec light, Ray ray, Scene scene) {
+ Hit i = scene.intersect(new Hit(infinity, new Vec(0, 0, 0)), ray);
+ if (i.lambda == infinity) return 0;
+ Vec o = add(ray.orig, add(scale(i.lambda, ray.dir),
+ scale(delta, i.normal)));
+ double g = dot(i.normal, light);
+ if (g >= 0) return 0.0;
+ Ray sray = new Ray(o, scale(-1, light));
+ Hit si = scene.intersect(new Hit(infinity, new Vec(0, 0, 0)), sray);
+ return (si.lambda == infinity ? -g : 0);
+ }
+ static Scene create(int level, Vec c, double r) {
+ Sphere sphere = new Sphere(c, r);
+ if (level == 1) return sphere;
+ Group group = new Group(new Sphere(c, 3*r));
+ group.objs.Add(sphere);
+ double rn = 3*r/Math.Sqrt(12);
+ for (int dz=-1; dz<=1; dz+=2)
+ for (int dx=-1; dx<=1; dx+=2) {
+ Vec c2 = new Vec(c.x+dx*rn, c.y+rn, c.z+dz*rn);
+ group.objs.Add(create(level-1, c2, r/2));
+ }
+ return group;
+ }
+ static void run(int n, int level, int ss) {
+ Scene scene = create(level, new Vec(0, -1, 0), 1);
+ System.Console.Write("P5\n"+n+" "+n+"\n255\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) {
+ Vec d = new Vec(x+dx*1.0/ss-n/2.0, y+dy*1.0/ss-n/2.0, n);
+ Ray ray = new Ray(new Vec(0, 0, -4), unitise(d));
+ g += ray_trace(unitise(new Vec(-1, -3, 2)),
+ ray, scene);
+ }
+ System.Console.Write((char)(.5+255*g/(ss*ss)));
+ }
+ }
+
+ public static void Main(String[] args) {
+ run(int.Parse(args[1]),
+ int.Parse(args[0]), 4);
+ }
+}
More information about the svn
mailing list