### Raytraced Sphere #3

I have combined the raytraced scene of turtletoy.net/turtle/11075dfee0 with the circle-packing algorithm of turtletoy.net/turtle/f9915c1d89 to get some sort of dithering.

#raytracer #pixels #rays #dithering

Created by reinder on 2018/12/29
273
0

```// Raytraced Sphere #3. Created by Reinder Nijhoff 2018
// @reindernijhoff
//
// https://turtletoy.net/turtle/7367ba3a0c
//

Canvas.setpenopacity(1);

const canvas_size = 95;

const light_position = [-2,3,-4];
const ro = [0,0,-3.5];
const sphere_pos = [-.2,0,0];

const max_tries = 400;
const circle_buckets = [];

const circles = [];

const turtle = new Turtle();

for (let i=0; i<circle_num_buckets+2; i++) {
circle_buckets[i]=[];
for (let j=0; j<circle_num_buckets+2; j++) {
circle_buckets[i][j] = [];
}
}

let coord_found = false;
let tries = 0;
const drdr = r*r*2;

while (!coord_found && tries < max_tries) {
tries ++;
const x = Math.random() * (canvas_size-r)*2 -canvas_size + r;
const y = Math.random() * (canvas_size-r)*2 -canvas_size + r;
let possible = true;

const xb = Math.max(0,((.5*x/canvas_size+.5)*circle_num_buckets)|0);
const yb = Math.max(0,((.5*y/canvas_size+.5)*circle_num_buckets)|0);

for (let xbi = Math.max(0,xb-1); xbi<xb+2 && possible; xbi++) {
for (let ybi = Math.max(0,yb-1); ybi<yb+2 && possible; ybi++) {
const circles = circle_buckets[xbi][ybi];
for (let i=0; i<circles.length && possible; i++) {
const dx = circles[i][0] - x;
const dy = circles[i][1] - y;

if ( dx*dx + dy*dy < drdr) {
possible = false;
break;
}
}
}
}
if (possible) {
coord_found = true;
draw_circle(x,y,t, r);
circle_buckets[xb][yb].push([x,y]);
return true;
}
}
return false;
}

function draw_circle(x,y,t,r) {
const intensity = get_image_intensity(x/canvas_size, y/canvas_size);
// use intensity squared because it looks better
turtle.penup();
turtle.pendown();
}
}

function walk(i) {
}
}

function get_image_intensity(x,y) {
const rd = normalize3([x,-y,2]);
let normal;
let light = 0;
let hit;
let plane_hit = false;

let dist = intersect_sphere(ro, rd, sphere_pos, 1);
if (dist > 0) {
normal = normalize3(hit);
} else {
dist = 10000;
}
if (rd[1] < 0) {
const plane_dist = -1/rd[1];
if (plane_dist < dist) {
dist = plane_dist;
plane_hit = true;
normal = [0,1,0];
}
}

if (dist > 0 && dist < 100) {
let vec_to_light = sub3(hit, light_position);
const light_dist_sqr = dot3(vec_to_light, vec_to_light);

vec_to_light = scale3(vec_to_light, -1/Math.sqrt(light_dist_sqr));

let light = dot3(normal, vec_to_light);
light *= 30 / light_dist_sqr;

if (plane_hit && intersect_sphere(hit, vec_to_light, sphere_pos, 1) > 0) {
light = 0;
}

return Math.sqrt(Math.min(1, Math.max(0,light)));
} else {
return 0;
}
}

const scale3=(a,b)=>[a[0]*b,a[1]*b,a[2]*b];
const len3=(a)=>Math.sqrt(dot3(a,a));
const normalize3=(a)=>scale3(a,1/len3(a));