UNPKG

vectorious-plus

Version:

A high performance linear algebra library.

142 lines (118 loc) 3.44 kB
(function (){ // Ported from Rust from https://gist.github.com/joshmarinacci/c84d0979e100d107f685 http://joshondesign.com/2014/09/17/rustlang 'use strict'; var Vector = require('../vectorious').Vector, add = Vector.add, subtract = Vector.subtract, scale = Vector.scale, dot = Vector.dot, render = process.stdout.write.bind(process.stdout); function Ray(orig, dir) { this.orig = orig; this.dir = dir; } function Sphere(center, radius, color) { this.center = center; this.radius = radius; this.color = color; } Sphere.prototype.normal = function normal(pt) { return subtract(pt, this.center).normalize(); } function Light(position, color) { this.position = position; this.color = color; } function Hit(obj, value) { this.obj = obj; this.value = value; } function shadePixel(ray, obj, tval) { var pi = add(ray.orig, scale(ray.dir, tval)); var color = diffuseShading(pi, obj, LIGHT1); var col = (color.data[0] + color.data[1] + color.data[2]) / 3.0; return Math.floor(col * 6.0); } function intersectSphere(ray, center, radius) { var l = subtract(center, ray.orig); var tca = l.dot(ray.dir); if (tca < 0) { return null; } var d2 = dot(l, l) - tca * tca; var r2 = radius * radius; if (d2 > r2) { return null; } var thc = Math.sqrt(r2 - d2); var t0 = tca - thc; if (t0 > 1e4) { return null; } return t0; } function clamp(x, a, b) { if (x < a) return a; if (x > b) return b; return x; } function diffuseShading(pi, obj, light) { var n = obj.normal(pi); var lam1 = subtract(light.position, pi).normalize().dot(n); var lam2 = clamp(lam1, 0.0, 1.0); return scale(light.color, lam2 * 0.5).add(scale(obj.color, 0.3)); } function range(lo, hi, cb) { for (var i = lo; i < hi; i++) { cb(i); } } // declare colors var WHITE = new Vector([1.0, 1.0, 1.0]), RED = new Vector([1.0, 0.0, 0.0]), GREEN = new Vector([0.0, 1.0, 0.0]), BLUE = new Vector([0.0, 0.0, 1.0]); // declare lighting var LIGHT1 = new Light(new Vector([0.7, -1.0, 1.7]), WHITE) // declare pixel intensities & screen size var lut = ['.', '-', '+', '*', 'X', 'M'], w = 20 * 4, h = 10 * 4; // declare scene var scene = [ new Sphere(new Vector([-1.0, 0.0, 3.0]), 0.3, RED), new Sphere(new Vector([0.0, 0.0, 3.0]), 0.8, GREEN), new Sphere(new Vector([1.0, 0.0, 3.0]), 0.4, BLUE) ]; // render scene range(0, h, function row(j) { range(0, w, function col(i) { var fw = parseFloat(w), fi = parseFloat(i), fj = parseFloat(j), fh = parseFloat(h); var ray = new Ray( new Vector([0.0, 0.0, 0.0]), new Vector([(fi - fw/2.0)/fw, (fj - fh/2.0)/fh, 1.0]).normalize() ) var hit, minRet, pixel; for (var k = 0; k < scene.length; k++) { var obj = scene[k]; var ret = intersectSphere(ray, obj.center, obj.radius); if (!ret) continue; // draw the closest intersecting point if (!minRet || ret < minRet) { minRet = ret; hit = new Hit(obj, ret); } } if (hit) { pixel = lut[shadePixel(ray, hit.obj, hit.value)]; } else { pixel = ' '; } render(pixel); }); render('\n'); }); }());