5

I'm pretty new and learning p5.js, and I am trying to make a 3D coronavirus in p5.js with a sphere and a bunch of cylinders..

You can see my sketch here: https://editor.p5js.org/zzzzzij/sketches/frE9-37R

    var sketch = function (p) {
      with(p) {

        let angle = 0;

        p.setup = function() {
          createCanvas(400, 400, WEBGL);
        };
    
        p.draw = function() {
          ambientLight(255);
          background(175);
          noStroke();
          rotateY(angle);
          rotateZ(angle*0.8);
          normalMaterial();

          push();
          rotateY(PI);
          sphere(100);
          pop();

          push();
          for (i = 0; i < 24; i ++) {
            rotateZ(PI/6);
            push();
            translate (0, -21*5, 0*5);
            rotateY(PI/18);
            rotateX(0);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/5);
            push();
            translate (0, -19*5, 9*5);
            rotateY(PI/18);
            rotateX(-PI/8);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/4);
            push();
            translate (0, -15*5, 15*5);
            rotateY(PI/18);
            rotateX(-PI/4);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/3);
            push();
            translate (0, -9*5, 19*5);
            rotateY(PI/18);
            rotateX(-PI/2.5);
            cylinder (6, 20);
            pop();
          }  
            
          for (i = 0; i < 5; i ++) {
            rotateZ(0);
            push();
            translate (0, 0*5, 21*5);
            rotateY(0);
            rotateX(-PI/2);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 5; i ++) {
            rotateZ(0);
            push();
            translate (0, 0*5, -21*5);
            rotateY(0);
            rotateX(-PI/2);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/3);
            push();
            translate (0, 9*5, -19*5);
            rotateY(-PI/18);
            rotateX(-PI/2.5);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/4);
            push();
            translate (0, 15*5, -15*5);
            rotateY(-PI/18);
            rotateX(-PI/4);
            cylinder (6, 20);
            pop();
          } 

          for (i = 0; i < 24; i ++) {
            rotateZ(PI/5);
            push();
            translate (0, 19*5, -9*5);
            rotateY(-PI/18);
            rotateX(-PI/8);
            cylinder (6, 20);
            pop();
          } 
          
          pop();
            
          angle+=0.01;
        };
     
      }
    };
    
    let node = document.createElement('div');
    window.document.getElementById('p5-container').appendChild(node);
    new p5(sketch, node);
body {
  background-color:#e9e9e9;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.10.2/p5.js"></script>
<div id="p5-container"></div>

Since I need every cylinder to point to a different direction, I've come up with using a bunch of for loops, doing one belt of cylinders after another spaced out along Z axis, every time the loop shrinks and rotates along X and Y a bit more.

As you can see, this has resulted for me in 7 for loops. And 3 of them just have some negative values of the other 3 to complete the ball.

I'm just wondering if there's a way to write these for loops in a nested loop? I've thought through it but just couldn't think of a solution...

Or if anyone has a better way to write these cylinder loops?

Thank you!

Dominique Fortin
  • 2,212
  • 15
  • 20
zzzzziji
  • 51
  • 1
  • After some research, I think I should go for the fractal tree approach instead of this for loop...gonna keep trying here ;) – zzzzziji Mar 09 '20 at 18:49
  • See the answers to the question [Evenly distributing n points on a sphere](https://stackoverflow.com/q/9600801/50065). – BioGeek Mar 10 '20 at 15:30
  • Have you considered using vectors to draw your sphere. Then you can have one for loop and draw a cylinder at the origin of each vector? Here are two video tutorials you might find helpful [Spherical Geometry](https://www.youtube.com/watch?v=RkuBWEkBrZA) and [Terrain Generation with Perlin Noise in Processing](https://www.youtube.com/watch?v=IKB1hWWedMk) – programming_ritual May 11 '21 at 10:43

1 Answers1

1

Here is a simple solution. What I have done in the following code, is that I first calculated the position of each vertex according to the number of total vertices and store them in a 2D array called globe! This will allow you to store information that can be used later in the code to draw the sphere and cylinders in a singular for-loop (each)!

I then created a sphere using triangles (in other words vertices, edges and faces) from the information stored in globe. You will notice that instead of cylinders I draw spheres. If you try changing that to cylinders it won't look very attractive. I'm not very good at mathematics but you can fix that issue by calculating the normals of each vertex. You may find this A Unit Vector (Normalize) - The Nature of Code and normalize() helpful but keep in mind that you will need to convert that from 2D to 3D!

const globe = []; //Holds a 2D array of vectors (v1,v2)
const r = 70; //Radius of circle
const total = 15; //number of vertices
let angleX = 0; //Rotate X axis
let angleY = 0; //Rotate Y axis

function setup() {
  createCanvas(300, 200, WEBGL);

  //Calculate vectors according to number of vertices given
  for (let i = 0; i < total + 1; i++) {
    globe[i] = []; //Create 2D array to hold vertices
    const lat = map(i, 0, total, 0, PI);
    for (let j = 0; j < total + 1; j++) {
      const lon = map(j, 0, total, 0, TWO_PI);
      const x = r * sin(lat) * cos(lon);
      const y = r * sin(lat) * sin(lon);
      const z = r * cos(lat);
      globe[i][j] = createVector(x, y, z); //Store vertices in 2D array
    }
  }
}

function draw(){
  background(51);
  rotateX(angleX);
  rotateY(angleY);
  fill(255);
  stroke(1);
  //Draw Sphere using globe 2D array
  for (let i = 0; i < total; i++) {
    beginShape(TRIANGLE_STRIP);
    for (let j = 0; j < total + 1; j++) {
      const v1 = globe[i][j];
      vertex(v1.x, v1.y, v1.z);
      const v2 = globe[i + 1][j];
      vertex(v2.x, v2.y, v2.z);
      vertices = [v1,v2];
    }
    endShape();
  }
  
  //Draw Cylinders
  for (i = 0; i < total; i ++) {
    for (j = 0; j < total; j ++) {
      const v1 = globe[i][j];
      const v2 = globe[i + 1][j];
      
      push();
      noStroke();
      translate(v1.x,v1.y,v1.z)
      
      normalMaterial();
      sphere(3,5);
      pop();
    }
  } 
  
  //Rotate on X & Y axes 
  angleX += 0.005;
  angleY += 0.006;
  
}
html, body {
  margin: 0;
  padding: 0;
}
canvas {
  display: block;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />

  </head>
  <body>
    <script src="sketch.js"></script>
  </body>
</html>