Some interesting patterns:
- Light Transport (variation)
- Light Transport (variation)
- Light Transport (variation)
Log in to post a comment.
// LL 2021 const rays = 70000; // min=100 max=200000 step=1 const objects = 15; // min=0 max=50 step=1 const object_radius = 10; // min=1 max=30 step=1 const reflection_factor = 0.9; // min=0 max=1 step=0.001 const seed=0; /// min=0 max=100 step=1 Canvas.setpenopacity(-Math.max(0.05, 1/rays)); //Canvas.setpenopacity(-0.1); const turtle = new Turtle(); const ray_x = 0; // min=-100 max=100 step=1 const ray_y = 0; // min=-100 max=100 step=1 const ray_dir = -1; // min=0 max=1 step=0.001 const ray_spread = 0.01; // min=0 max=1 step=0.001 const origin_x = ray_x; const origin_y = ray_y; const origin_dir_x = Math.cos((ray_dir<0?random():ray_dir) * Math.PI * 2); const origin_dir_y = Math.sin((ray_dir<0?random():ray_dir) * Math.PI * 2); const origin_spread = Math.PI * (ray_spread**3) * 2; const draw_objects=1; // min=0 max=1 step=1 (No,Yes) var whole_scene; var rng; var current_ray = null; console.clear(); function walk(i, t) { if (i==0) { rng = new RNG(seed); whole_scene = new Scene(); } if (draw_objects) whole_scene.draw(); if (current_ray === null || current_ray.done) { const dir_x = t<1 ? Math.cos(t * Math.PI * 2) : origin_dir_x; const dir_y = t<1 ? Math.sin(t * Math.PI * 2) : origin_dir_y; current_ray = new Ray(whole_scene, origin_x, origin_y, dir_x, dir_y, origin_spread); } whole_scene.shoot(current_ray); return i+1 < rays; } class Sphere { constructor(x, y, r) { this.x = x; this.y = y; this.r = r; } draw() { turtle.jump(this.x + this.r, this.y); const step = 1/20; for (var a=step; a<1+step*0.1; a+=step) { turtle.goto(this.x + Math.cos(a * Math.PI * 2) * this.r, this.y + Math.sin(a * Math.PI * 2) * this.r); } } getIntersection(ray) { const fx = ray.x - this.x, fy = ray.y - this.y; const a = dot(ray.dir_x, ray.dir_y, ray.dir_x, ray.dir_y); const b = 2 * dot(fx, fy, ray.dir_x, ray.dir_y); const c = dot(fx, fy, fx, fy) - this.r * this.r; const discriminant2 = b * b - 4 * a * c; if (discriminant2 < 0) { return false; } else { const discriminant = Math.sqrt(discriminant2); const t1 = (-b - discriminant) / (2 * a); const t2 = (-b + discriminant) / (2 * a); return (t1 > 0.1) ? t1 : (t2 > 0.1) ? t2 : false; } } getNormalAtPoint(x, y) { var nx = x - this.x, ny = y - this.y; const len = Math.hypot(nx, ny); if (len > 0.01) { nx /= len; ny /= len; } return [ nx, ny ]; } } class Scene { constructor() { this.objects = []; const d = 65; const r = object_radius; for (var a=0; a<1; a+=1/objects) { this.objects.push( new Sphere( d * Math.cos(a * Math.PI * 2 - Math.PI / 2), d * Math.sin(a * Math.PI * 2 - Math.PI / 2), r) ); } } draw() { this.objects.forEach(o => o.draw()); } shoot(ray) { if (ray.done) return; var closest_object = null; var min_t = 1000; this.objects.forEach(o => { const t = o.getIntersection(ray); if (t && (t < min_t)) { min_t = t; closest_object = o; } }); turtle.jump(ray.x, ray.y); const new_x = ray.x + ray.dir_x * min_t; const new_y = ray.y + ray.dir_y * min_t; turtle.goto(new_x, new_y); if (closest_object !== null) { const normal = closest_object.getNormalAtPoint(new_x, new_y); ray.reflect(new_x, new_y, normal[0], normal[1]); } else { ray.done = true; } } } class Ray { constructor(scene, x, y, dx, dy, ds) { this.x = x; this.y = y; this.done = false; this.scene = scene; const angle = random() * ds - ds / 2; this.dir_x = rotX(dx, dy, angle); this.dir_y = rotY(dx, dy, angle); const len = Math.hypot(this.dir_x, this.dir_y); if (len < 0.001) this.done = true; this.dir_x /= len; this.dir_y /= len; } reflect(x, y, nx, ny) { this.x = x; this.y = y; const dir = random() < reflection_factor ? 1 : -1; const dotDN = dot(this.dir_x, this.dir_y, nx, ny); const reflect_x = this.dir_x - 2 * dotDN * dir * nx; const reflect_y = this.dir_y - 2 * dotDN * dir * ny; this.dir_x = reflect_x; this.dir_y = reflect_y; } } function dot(v1x, v1y, v2x, v2y) { return v1x * v2x + v1y * v2y; } function rotX(x, y, a) { return Math.cos(a) * x - Math.sin(a) * y; } function rotY(x, y, a) { return Math.sin(a) * x + Math.cos(a) * y; } function random() { return Math.random(); } //function random() { return rng.nextFloat(); } // Minified Random Number Generator from https://turtletoy.net/turtle/ab7a7e539e function RNG(t){return new class{constructor(t){this.m=2147483648,this.a=1103515245,this.c=12345,this.state=t||Math.floor(Math.random()*(this.m-1))}nextFloat(){return this.state=(this.a*this.state+this.c)%this.m,this.state/(this.m-1)}}(t)}