[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