Ez-wanderer
Log in to post a comment.
// LL 2021
const steps = 1000; // min=10 max=10000 step=1
const density = 400; // min=10 max=1000 step=1
const opacity = -0.25; // min=-1 max=1 step = 0.01
const camera_angle = 0.14; // min=0 max=1 step=0.01
const camera_height = 1; // min=0 max=3 step=0.01
const camera_distance = 2; // min=0.1 max=5 step=0.01
Canvas.setpenopacity(opacity);
let grid;
let current_pos;
const turtle = new Turtle();
function walk(i, t) {
if (i==0) {
reset_random();
cameraPos = [camera_distance * Math.cos(Math.PI * 2 * (camera_angle + t)), camera_height, camera_distance * Math.sin(Math.PI * 2 * (camera_angle + t))];
viewProjectionMatrix = setupCamera(cameraPos, cameraLookAt);
reset_current_pos();
grid = {};
} else if (i > steps * density) {
return false;
}
const saved_pos = [...current_pos];
var retries = 50;
while (retries > 0) {
retries--;
if (retries < 1) {
// Stuck, move somewhere else
reset_current_pos();
return true;
};
const chance = Math.floor(random() * 6);
switch (chance) {
case 0: if (move( 1, 0, 0)) retries = 0; break;
case 1: if (move(-1, 0, 0)) retries = 0; break;
case 2: if (move( 0, 1, 0)) retries = 0; break;
case 3: if (move( 0, -1, 0)) retries = 0; break;
case 4: if (move( 0, 0, 1)) retries = 0; break;
case 5: if (move( 0, 0, -1)) retries = 0; break;
}
}
const p1 = project(saved_pos);
const p2 = project(current_pos);
turtle.jump(p1);
turtle.goto(p2);
return true;
}
function reset_current_pos() {
current_pos = [ Math.round(density * random()), Math.round(density * random()), Math.round(density * random()) ];
}
function move(dx, dy, dz) {
if (current_pos[0] + dx < 0) return false;
if (current_pos[0] + dx > density) return false;
if (current_pos[1] + dy < 0) return false;
if (current_pos[1] + dy > density) return false;
if (current_pos[2] + dz < 0) return false;
if (current_pos[2] + dz > density) return false;
const x = current_pos[0] - density / 2;
const y = current_pos[1] - density / 2;
const z = current_pos[2] - density / 2;
const distance = Math.sqrt(x*x + y*y + z*z);
if (distance > density / 2) return false;
const index = pos_to_index(current_pos[0] + dx, current_pos[1] + dy, current_pos[2] + dz);
if (grid[index] == true) return false;
current_pos[0] += dx;
current_pos[1] += dy;
current_pos[2] += dz;
grid[index] = true;
return true;
}
function project(pos) {
const x = pos[0] / density - 0.5, y = pos[1] / density - 0.5, z = pos[2] / density - 0.5;
const p = transform4([x, z, y, 1], viewProjectionMatrix);
const s = 50;
return [p[0]/p[3]*s, -p[1]/p[3]*s];
}
function pos_to_index(x, y, z) {
const index = Math.round(x) + Math.floor(y*density) + Math.floor(z*density*density);
return index;
}
// Cached random for animations
function random() { while (rand_index >= rand_cache.length) rand_cache.push(Math.random()); return rand_cache[rand_index++]; }
function reset_random() { rand_index = 0; }
const rand_cache = [];
var rand_index = 0;
////////////////////////////////////////////////////////////////
// Projection from reinder's https://turtletoy.net/turtle/b3acf08303
let cameraPos, viewProjectionMatrix;
const cameraLookAt = [0,0,0];
function setupCamera(t,e){const m=lookAt4m(t,e,[0,1,0]),n=perspective4m(.25,1);return multiply4m(n,m)}
function lookAt4m(o,n,r){const s=new Float32Array(16);n=normalize3(sub3(o,n)),r=normalize3(cross3(r,n));const t=normalize3(cross3(n,r));return s[0]=r[0],s[1]=t[0],s[2]=n[0],s[3]=0,s[4]=r[1],s[5]=t[1],s[6]=n[1],s[7]=0,s[8]=r[2],s[9]=t[2],s[10]=n[2],s[11]=0,s[12]=-(r[0]*o[0]+r[1]*o[1]+r[2]*o[2]),s[13]=-(t[0]*o[0]+t[1]*o[1]+t[2]*o[2]),s[14]=-(n[0]*o[0]+n[1]*o[1]+n[2]*o[2]),s[15]=1,s}
function perspective4m(t,n){const e=new Float32Array(16).fill(0,0);return e[5]=1/Math.tan(t/2),e[0]=e[5]/n,e[10]=e[11]=-1,e}
function multiply4m(t,r){const l=new Float32Array(16);for(let n=0;16>n;n+=4)for(let o=0;4>o;o++)l[n+o]=r[n+0]*t[0+o]+r[n+1]*t[4+o]+r[n+2]*t[8+o]+r[n+3]*t[12+o];return l}
function transform4(r,n){const t=new Float32Array(4);for(let o=0;4>o;o++)t[o]=n[o]*r[0]+n[o+4]*r[1]+n[o+8]*r[2]+n[o+12];return t}
function normalize3(a) { return scale3(a,1/len3(a)); }
function scale3(a,b) { return [a[0]*b,a[1]*b,a[2]*b]; }
function len3(a) { return Math.sqrt(dot3(a,a)); }
function sub3(a,b) { return [a[0]-b[0],a[1]-b[1],a[2]-b[2]]; }
function dot3(a,b) { return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]; }
function cross3(a,b) { return [a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]; }