Search code examples
webglwebgl2

Strange errors during drawing hollow circles in the 3D space


I am trying to draw two hollow circles that are surrounding a cube which is located at the 0, 0, 0 position..

so far I've implemented the cube and the two circles here is what I get.

The cube and the two circles

there are two strange things happening here.

One is that I want to draw the circles but I can see the lines radiating from the origin.

and two is that interpolated colors, even though I set just one color for the fragment shader.

here is you can see clearly those lines with interpolated color...

Strange colors..

here is my vertex shader code and the fragment shader code

"use strict";
const loc_aPosition = 1;
const loc_aColor = 2;
const loc_UVCoord = 3;
const VSHADER_SOURCE = 
`#version 300 es
layout(location=${loc_aPosition}) in vec4 aPosition;
layout(location=${loc_aColor}) in vec4 aColor;
layout(location=${loc_UVCoord}) in vec2 UVCoord;
out vec4 vColor;
out vec2 vUVCoord;
uniform mat4 uMVP;
void main()
{
    gl_Position = uMVP * aPosition;
    vColor = aColor;
    vUVCoord = UVCoord;
}`;

const FSHADER_SOURCE =
`#version 300 es
precision mediump float;
in vec4 vColor;
out vec4 fColor;
void main()
{
    fColor = vColor;
}`;

and the initilize functions for the two circles and there is the only difference is the target plane.

function init_equator(gl)
{
  let vertices = []; // for the vertices
  let color = [1, 0, 0]; // red color
  for(var i = 0; i <= 360; i+=10)
  {
    let j = i * Math.PI/180;
    let vert = [R * Math.cos(j), 0, R * Math.sin(j)]; // drawing a circle at the XZ plane since it has to be an equator for the cube...
    vertices.push( vert[0], vert[1], vert[2] );   // push the vertices
    vertices.push( color[0], color[1], color[2]); // set the color
  }  
  const SZ = vertices.BYTES_PER_ELEMENT;

  let vao = gl.createVertexArray();
  gl.bindVertexArray(vao);
  let vbo = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

  gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0); // stride is 6, 3 for positions and 3 for the color
  gl.enableVertexAttribArray(loc_aPosition);


  gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3); // stride is 6, offset is this is because 3 color elements are located after 3 position elements..
  gl.enableVertexAttribArray(loc_aColor);

  gl.bindVertexArray(null);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  return { vao, n : vertices.length / 3 }; // since it has three coordinates so devide by 3
}


function init_latitude(gl)
{
  let vertices = []; // for the vertices
  let color = [1, 0, 0]; // supposed to be the red
  for(var i = 0; i <= 360; i+=10)
  {
    let j = i * Math.PI/180;
    let vert = [0, R * Math.cos(j), R * Math.sin(j)]; // drawing a circle on the YZ plane
    vertices.push( vert[0], vert[1], vert[2] ); 
    vertices.push( color[0], color[1], color[2]);   
  }  
  const SZ = vertices.BYTES_PER_ELEMENT;

  let vao = gl.createVertexArray();
  gl.bindVertexArray(vao);
  let vbo = gl.createBuffer();

  gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

  gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0); // stride is 6, 3 for positions and 3 for the color
  gl.enableVertexAttribArray(loc_aPosition);

  gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3); // stride is 6, offset is this is because 3 color elements are located after 3 position elements..
  gl.enableVertexAttribArray(loc_aColor);

  gl.bindVertexArray(null);
  gl.bindBuffer(gl.ARRAY_BUFFER, null);

  return { vao, n : vertices.length / 3 }; // since it has three coordinates so devide by 3
}

I refer these drawing fucntions from here drawing circle

in the main function I called the draw function like this..

........
MVP.setOrtho(LEFT, RIGHT, BOTTOM, TOP, NEAR, FAR); // setting MVP matrix to orthographic mode
    MVP.lookAt(FIXED_X, FIXED_Y, FIXED_Z, 0,0,0, 0,1,0); // Eye position x, y, z Look at position 0, 0, 0 Up vector 0, 1, 0
    gl.uniformMatrix4fv(loc_MVP, false, MVP.elements);
    gl.bindVertexArray(cube.vao);
    gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
    gl.bindVertexArray(null);
    gl.bindVertexArray(equator.vao);
    gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
    gl.bindVertexArray(null);
    gl.bindVertexArray(latitudeCircle.vao);
    gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
    gl.bindVertexArray(null);

I have no ideas why the lines are radiating from the origin and the mixed color...

could somebody help me?


Solution

  • this line, which appears twice in the code you posted

    const SZ = vertices.BYTES_PER_ELEMENT;
    

    is SZ will be undefined. vertices is a native JavaScript array, not a typedarray array like Float32Array. After that every calculation with SZ will be 0 or NaN

    In other words these lines

      gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, SZ * 6, 0);
      gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, SZ * 6, SZ * 3); 
    

    Will be

      gl.vertexAttribPointer(loc_aPosition, 3, gl.FLOAT, false, 0, 0);
      gl.vertexAttribPointer(loc_aColor, 3, gl.FLOAT, false, 0, 0); 
    

    Which means every other position is a color, and every other color is a position which explains why lines go to the center and why colors are interpolated.

    Note that if you had stepped through the code in the debugger you'd have probably seen this issue so it would be good to learn how to use the debugger.

    Also FYI unrelated to your issue you don't need to call gl.bindVertexArray twice in a row, once with null and once with the next thing you want to draw with.

    this

        gl.bindVertexArray(cube.vao);
        gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
        gl.bindVertexArray(null);
        gl.bindVertexArray(equator.vao);
        gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
        gl.bindVertexArray(null);
        gl.bindVertexArray(latitudeCircle.vao);
        gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
        gl.bindVertexArray(null);
    

    can just be this

        gl.bindVertexArray(cube.vao);
        gl.drawElements(gl.TRIANGLES, cube.n, gl.UNSIGNED_BYTE, 0)
        gl.bindVertexArray(equator.vao);
        gl.drawArrays(gl.LINE_LOOP, 0, equator.n);
        gl.bindVertexArray(latitudeCircle.vao);
        gl.drawArrays(gl.LINE_LOOP, 0, latitudeCircle.n);
        gl.bindVertexArray(null);  // this is also not technically needed
    

    Also also, you can use the spread operator.

    This

        vertices.push( vert[0], vert[1], vert[2] );   // push the vertices
        vertices.push( color[0], color[1], color[2]); // set the color
    

    can be this

        vertices.push( ...vert );   // push the vertices
        vertices.push( ...color ); // set the color
    

    Also you might find these tutorials useful.