createCanvas(windowWidth, windowHeight);
pg = createGraphics(width, height, WEBGL);
for (let i = 0; i < n; i++) {
if (!objects[i].exist) continue;
pg.directionalLight(255, 255, 255, 0.5, 0.5, -1);
pg.fill(objects[i].color);
pg.translate(objects[i].position);
pg.rotateY(objects[i].rotation);
objects[i].position.y -= 2;
objects[i].rotation += 0.02;
if (objects[i].position.y < -height * 2) objects[i].position.set(random(-width / 2, width / 2), height * 2, objects[i].position.z -= 500);
if (objects[i].position.z < -1000) objects[i].exist = false;
const v = new p5.Vector(mouseX - width / 2, mouseY - height / 2, 0);
if (vectors.length > 10 && v.dist(vectors[0]) < 20) {
} else if (vectors.length > 0 && v.dist(vectors[vectors.length - 1]) > 10) {
translate(width / 2, height / 2);
stroke(closed ? color(200, 50, 50) : 60);
circle(vectors[0].x, vectors[0].y, 10);
for (let i = 0; i < vectors.length; i++) {
vertex(vectors[i].x, vectors[i].y);
circle(vectors[vectors.length - 1].x, vectors[vectors.length - 1].y, 10);
text("Draw a shape with your mouse", width / 2, height / 2);
function mousePressed() {
vectors = [new p5.Vector(mouseX - width / 2, mouseY - height / 2, 0)];
function mouseReleased() {
const pos = findCenter();
const col = color(`hsb(${int(random(36000) % 360)}, 100%, 80%)`);
objects.push({position : pos, rotation : 0, color : col, exist : true});
pg.fill(objects[n].color);
pg.translate(objects[n].position);
pg.rotateY(objects[n].rotation);
let center = new p5.Vector();
for (let i = 0; i < vectors.length; i++) {
center.div(vectors.length);
for (let i = 0; i < vectors.length; i++) {
const gId = `shape3D${n}`;
if (!pg._renderer.geometryInHash(gId)) {
const shapeGeom = new p5.Geometry();
const z1 = new p5.Vector(0, 0, 20);
const z2 = new p5.Vector(0, 0, -20);
let tesselateVertices = pg._renderer._triangulate(verticesToArray(vectors));
tesselateVertices = arrayToVertices(tesselateVertices);
tesselateVertices = verticesFilter(tesselateVertices);
for (let i=0; i<tesselateVertices.length; i++) {
shapeGeom.vertices.push(p5.Vector.add(tesselateVertices[i], z1));
for (let i=0; i<tesselateVertices.length; i++) {
shapeGeom.vertices.push(p5.Vector.add(tesselateVertices[tesselateVertices.length-(i+1)], z2));
for (let i=0; i<tesselateVertices.length * 2; i+=3) {
shapeGeom.faces.push([i, i+1, i+2]);
id = tesselateVertices.length * 2;
for (const ver of vectors) {
shapeGeom.vertices.push(p5.Vector.add(ver, z1));
shapeGeom.vertices.push(p5.Vector.add(ver, z2));
let len = vectors.length * 2;
for (let i=0; i<len; i+=2) {
shapeGeom.faces.push([id + i, id + i+1, id + (i+2)%len]);
shapeGeom.faces.push([id + (i+3)%len, id + (i+2)%len, id + i+1]);
shapeGeom.computeNormals();
shapeGeom._makeTriangleEdges()._edgesToVertices();
pg._renderer.createBuffers(gId, shapeGeom);
pg._renderer.drawBuffers(gId);
function verticesToArray(vertices) {
for (let ver of vertices) {
array = array.concat(ver.x, ver.y, ver.z);
function arrayToVertices(array) {
for (let i=0; i<array.length; i+=3) {
vertices.push(new p5.Vector(array[i], array[i+1], array[i+2]));
function verticesFilter(vertices) {
for (let i = 0; i < vertices.length; i += 3) {
let ba = p5.Vector.sub(vertices[i+1], vertices[i]);
let bc = p5.Vector.sub(vertices[i+1], vertices[i+2]);
let cross = p5.Vector.cross(ba, bc);
if (p5.Vector.mag(cross) != 0) {
filtered.push(vertices[i], vertices[i+1], vertices[i+2]);