Search code examples
javascriptgraphics3dp5.js

3D Sphere isn't rendered properly


I programmed a 3d sphere in javascript using p5.js and isn't rendered properly. You can see a lack of color in the last meridian and all the sphere isn't colored in the right manner. I tried a lot of things to fix this and isn't working.

Here's a image of what happen:

So why this happen?

Can you fix this?

Here's the code:

var points;
var total = 25;
var r = 150;

function setup()
{
  createCanvas(600, 400, WEBGL);
  colorMode(HSB);
  points = new Array(total + 1);

  for (let i = 0; i <= total; i++)
  {
    points[i] = new Array(total);
    var lon = map(i, 0, total, -PI, PI);
    for (let j = 0; j <= total; j++)
    {
      points[i][j] = new p5.Vector();
      var lat = map(j, 0, total, - (PI /2), (PI / 2));
      points[i][j].x = r * sin(lon) * cos(lat);;
      points[i][j].y = r * sin(lon) * sin(lat);
      points[i][j].z = r * cos(lon);
    }
  }

}

angle = 0;

function draw()
{
  background(0);
  fill(255)
  rotateX(angle);
  stroke(255);
  for (let i = 0; i < total; i++)
  {
    <!-- noFill(); -->
    var hue = map(i, 0, total, 0, 255);
    beginShape();
    for (let j = 0; j < total; j++)
    {
      fill(hue, 255, 255);
      vertex(points[i][j+1].x, points[i][j+1].y, points[i][j+1].z);
      vertex(points[i+1][j+1].x, points[i+1][j+1].y, points[i+1][j+1].z);
      vertex(points[i][j+1].x, points[i][j+1].y, points[i][j+1].z);
      vertex(points[i][j].x, points[i][j].y, points[i][j].z);
    }
    endShape();
  }
  angle += 0.01;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.js"></script>


Solution

  • There are 2 problems in your code:

    1. If you use beginShape, the default primitive type is a large polygon, but you want to draw QUADS

      beginShape();

      beginShape(QUADS);
      
    2. The vertices are wrong because points[i][j+1] is given twice, but points[i+1][j] is missing. Correct is:

      vertex(points[i][j+1].x, points[i][j+1].y, points[i][j+1].z);
      vertex(points[i+1][j+1].x, points[i+1][j+1].y, points[i+1][j+1].z);
      vertex(points[i+1][j].x, points[i+1][j].y, points[i+1][j].z);
      vertex(points[i][j].x, points[i][j].y, points[i][j].z);
      

    Also note that beginShape/endshape can be moved out of the outer loop. This way you don't have to start a new shape continuously, but the complete sphere can be drawn at once.

    var points;
    var total = 25;
    var r = 150;
    
    function setup()
    {
        createCanvas(600, 400, WEBGL);
        colorMode(HSB);
        points = new Array(total + 1);
    
        for (let i = 0; i <= total; i++)
        {
            points[i] = new Array(total);
            var lon = map(i, 0, total, -PI, PI);
            for (let j = 0; j <= total; j++)
            {
                points[i][j] = new p5.Vector();
                var lat = map(j, 0, total, - (PI /2), (PI / 2));
                points[i][j].x = r * sin(lon) * cos(lat);;
                points[i][j].y = r * sin(lon) * sin(lat);
                points[i][j].z = r * cos(lon);
            }
        }
    }
    
    var angle = 0;
    
    function draw()
    {
        background(0);
        fill(255)
        rotateX(angle);
        stroke(255);
        beginShape(QUADS);
        for (let i = 0; i < total; i++)
        {
            var hue = map(i, 0, total, 0, 255);
            fill(hue, 255, 255);
            for (let j = 0; j < total; j++)
            {
                vertex(points[i][j+1].x, points[i][j+1].y, points[i][j+1].z);
                vertex(points[i+1][j+1].x, points[i+1][j+1].y, points[i+1][j+1].z);
                vertex(points[i+1][j].x, points[i+1][j].y, points[i+1][j].z);
                vertex(points[i][j].x, points[i][j].y, points[i][j].z);
            }
        }
        endShape();
        angle += 0.01;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>