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]]; }