xxxxxxxxxx
239
let lines;
let near;
let far;
let mid;
let rot;
function setup() {
createCanvas(512, 512, WEBGL);
makeLines();
}
function addLine( P, Q )
{
const v = p5.Vector.sub( Q, P );
v.normalize();
const rp = P.z / 100.0;
const rq = Q.z / 100.0;
lines.push( {
P: P,
Q: Q,
v: v,
m : createTruncatedCone( rp, rq, 2 * P.dist( Q ), 24, 8, true, true )
});
}
function makeLines() {
lines = [];
const fov = PI / 3;
const asp = width / height;
const eyeZ = height / 2 / tan(PI / 6);
near = eyeZ / 10;
far = eyeZ * 10;
mid = 0.5 * (near + far);
const tf = tan(fov / 2);
const aspect = width / height;
const lo = 0.1;
const hi = 0.9;
for (let y = 0; y < 11; ++y) {
const h = lerp(-1, 1, y / 10);
let d = -lerp(near,far,random(lo, hi));
const l = createVector(d * tf * aspect, d * tf * h, d + mid);
d = -lerp(near,far,random(lo, hi));
const r = createVector(-d * tf * aspect, d * tf * h, d + mid);
addLine( l, r );
d = -lerp(near,far,random(lo, hi));
const t = createVector(d * tf * aspect * h, d * tf, d + mid);
d = -lerp(near,far,random(lo, hi));
const b = createVector(d * tf * aspect * h, -d * tf, d + mid);
// console.log( t.x, t.y, t.z, b.x, b.y, b.z );
addLine( t, b );
}
rot = createVector( random(-1,1), random(-1,1), random(-1, 1) );
rot.normalize();
}
function draw() {
background(255);
const Y = createVector(0,1,0);
const tf = tan(PI / 6);
const aspect = width / height;
const d = height / 2 / tf;
fill( 0 );
push();
translate(0, 0, d - mid );
const fc = frameCount % 250;
if( fc > 50 ) {
const ang = ease( (fc-50) / 200.0 ) * TWO_PI;
rotate( ang, rot );
}
for (let l of lines) {
const A = l.P;
const B = l.Q;
const axis = p5.Vector.cross( l.v, Y );
axis.normalize();
push();
translate( A.x, A.y, A.z );
const a = l.v.angleBetween( Y );
if( a > 1e-7 ) {
rotate( -a, axis );
}
translate( 0, A.dist(B) / 2 );
model( l.m );
pop();
}
pop();
}
function keyPressed()
{
if( key == ' ' ) {
makeLines();
} else if( key == 'g' ) {
saveGif("output", 250, { units: "frames", delay: 0 });
}
}
function ease( t )
{
return t * t * (3.0 - 2.0 * t);
}
// this code is lifted from https://editor.p5js.org/J_Silva/sketches/PVHYikYjQ
function createTruncatedCone(
bottomRadius,
topRadius,
height,
detailX,
detailY,
bottomCap,
topCap
) {
return new p5.Geometry(detailX, detailY, function () {
bottomRadius = bottomRadius <= 0 ? 1 : bottomRadius;
topRadius = topRadius < 0 ? 0 : topRadius;
height = height <= 0 ? bottomRadius : height;
detailX = detailX < 3 ? 3 : detailX;
detailY = detailY < 1 ? 1 : detailY;
bottomCap = bottomCap === undefined ? true : bottomCap;
topCap = topCap === undefined ? topRadius !== 0 : topCap;
const start = bottomCap ? -2 : 0;
const end = detailY + (topCap ? 2 : 0);
//ensure constant slant for interior vertex normals
const slant = Math.atan2(bottomRadius - topRadius, height);
const sinSlant = Math.sin(slant);
const cosSlant = Math.cos(slant);
let yy, ii, jj;
for (yy = start; yy <= end; ++yy) {
let v = yy / detailY;
let y = height * v;
let ringRadius;
if (yy < 0) {
//for the bottomCap edge
y = 0;
v = 0;
ringRadius = bottomRadius;
} else if (yy > detailY) {
//for the topCap edge
y = height;
v = 1;
ringRadius = topRadius;
} else {
//for the middle
ringRadius = bottomRadius + (topRadius - bottomRadius) * v;
}
if (yy === -2 || yy === detailY + 2) {
//center of bottom or top caps
ringRadius = 0;
}
y -= height / 2; //shift coordiate origin to the center of object
for (ii = 0; ii < detailX; ++ii) {
const u = ii / (detailX - 1);
const ur = 2 * Math.PI * u;
const sur = Math.sin(ur);
const cur = Math.cos(ur);
//VERTICES
this.vertices.push(
new p5.Vector(sur * ringRadius, y, cur * ringRadius)
);
//VERTEX NORMALS
let vertexNormal;
if (yy < 0) {
vertexNormal = new p5.Vector(0, -1, 0);
} else if (yy > detailY && topRadius) {
vertexNormal = new p5.Vector(0, 1, 0);
} else {
vertexNormal = new p5.Vector(
sur * cosSlant,
sinSlant,
cur * cosSlant
);
}
this.vertexNormals.push(vertexNormal);
//UVs
this.uvs.push(u, v);
}
}
let startIndex = 0;
if (bottomCap) {
for (jj = 0; jj < detailX; ++jj) {
const nextjj = (jj + 1) % detailX;
this.faces.push([
startIndex + jj,
startIndex + detailX + nextjj,
startIndex + detailX + jj,
]);
}
startIndex += detailX * 2;
}
for (yy = 0; yy < detailY; ++yy) {
for (ii = 0; ii < detailX; ++ii) {
const nextii = (ii + 1) % detailX;
this.faces.push([
startIndex + ii,
startIndex + nextii,
startIndex + detailX + nextii,
]);
this.faces.push([
startIndex + ii,
startIndex + detailX + nextii,
startIndex + detailX + ii,
]);
}
startIndex += detailX;
}
if (topCap) {
startIndex += detailX;
for (ii = 0; ii < detailX; ++ii) {
this.faces.push([
startIndex + ii,
startIndex + ((ii + 1) % detailX),
startIndex + detailX,
]);
}
}
});
}