WebGL vertex indexed drawing

Knowledge points

New drawing function gl.drawElements();

gl.drawArrays() directly calls the vertex array data, every time a straight line is drawn, two vertices need to be defined.

gl.drawElements() uses an index array to access the vertex data in the vertex array, can reuse the vertex data.

index array and vertex array

// 8 vertex coordinate arrays
var data=new Float32Array([
0.5, 0.5, 0.5,//vertex 0
-0.5, 0.5, 0.5,//vertex 1
-0.5, -0.5, 0.5,//vertex 2
0.5, -0.5, 0.5, // Vertex 3
0.5, 0.5, -0.5, //vertex 4
-0.5, 0.5, -0.5,//vertex 5
-0.5, -0.5, -0.5,//vertex 6
0.5, -0.5, -0.5, // Vertex 7
]);
// Vertex index array
var indexes = new Uint8Array([
  //The first four points correspond to the index value
  0, 1, 2, 3,//gl.LINE_LOOP mode draws a rectangular frame with four points
  //The last four vertices correspond to index values
  4, 5, 6, 7,//gl.LINE_LOOP mode draws a rectangular frame with four points
  //The corresponding index value of the corresponding point before and after
  0, 4, // two points draw a straight line
  1, 5,//two points draw a straight line
  2, 6,//two points draw a straight line
  3, 7//Two points draw a straight line
]);

Create a buffer of array indices

To operate the data of the index array, you need to add the data to the buffer (the vertex array must also be added to the buffer, which requires two buffer objects)

//Create a vertex buffer object
var buffer = gl. createBuffer();
// bind the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
//The vertex array data data is passed into the buffer
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

//Create index buffer object
var indexesBuffer = gl. createBuffer();
// bind the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexesBuffer);
//The index array indexes data is passed into the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexes, gl.STATIC_DRAW);

//The data in the buffer is passed to the position variable apos according to certain rules
gl.vertexAttribPointer(aposLocation, 3, gl.FLOAT, false, 0, 0);
//Allow data transfer
gl.enableVertexAttribArray(aposLocation);

The use of drawElements() adds a data type setting parameter, gl.UNSIGNED_BYTE.

After the data is processed, it can be rendered by drawElements(). (replaces drawArrays() method)

//LINE_LOOP mode draws the first four points
gl.drawElements(gl.LINE_LOOP,4,gl.UNSIGNED_BYTE,0);
//LINE_LOOP mode draws four points starting from the fifth point
gl.drawElements(gl.LINE_LOOP,4,gl.UNSIGNED_BYTE,4);
//8 points after drawing in LINES mode
gl.drawElements(gl.LINES, 8, gl.UNSIGNED_BYTE, 8);

Parameter 1: mode drawing mode (gl.LINE_LOOP, gl.LINES, gl.TRIANGLES, etc.)

Parameter 2: count number of vertices drawn (integer)

Parameter 3: type data type

gl.UNSIGNED_BYTE corresponds to Uint8Array,

gl.UNSIGNED_SHORT corresponds to Uint16Array

Parameter 4: Offset from which point to start drawing (integer, in bytes)

Note: count and offset refer to the index array of vertices

Summary:

Purpose: To solve the redundancy problem of vertex array data data,

① Define vertex array data, index array indexes,

② Create the buffer object of the vertex array and the index array and pass in the data (2 buffer objects),

③ Use gl.drawElements() to replace gl.drawArrays() to render graphics

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
</head>

<body>
  <canvas id="webgl" width="500" height="500" style="background-color: #0d72da"></canvas>
  <script>
    var canvasElement = document. getElementById('webgl');
    var gl = canvasElement. getContext('webgl');

    //Vertex shader source code
    var vertexShaderSource = '' +
      //attribute declares the vec4 type variable apos
      'attribute vec4 apos;' +
      'void main(){' +
      //Set the geometry axis rotation angle to 30 degrees, and convert the angle value to a floating point value
      'float radian = radians(30.0);' +
      // Solve the cosine value of the rotation angle
      'float cos = cos(radian);' +
      // Solve the sine of the rotation angle
      'float sin = sin(radian);' +
      //Refer to the calculation data above to create a rotation matrix around the x-axis
      // 1 0 0 0
      // 0 cosα sinα 0
      // 0 - sinα cosα 0
      // 0 0 0 1
      'mat4 mx = mat4(1,0,0,0,0,cos,-sin,0,0,sin,cos,0,0,0,0,1);' +
      //Refer to the calculation data above to create a rotation matrix around the y-axis
      // cosβ 0 sinβ 0
      // 0 1 0 0
      //-sinβ 0 cosβ 0
      // 0 0 0 1
      'mat4 my = mat4(cos,0,-sin,0, 0,1,0,0, sin,0,cos,0, 0,0,0,1);' +
      //Multiplication of two rotation matrices and vertex homogeneous coordinates
      ' gl_Position = mx*my*apos;' +
      '}';
    //Fragment shader source code
    var fragShaderSource = '' +
      'void main(){' +
      ' gl_FragColor = vec4(1.0,0.0,0.0,1.0);' +
      '}';


    //Initialize the shader
    var program = initShader(gl, vertexShaderSource, fragShaderSource);
    // Get the position variable apos of the vertex shader
    var aposLocation = gl. getAttribLocation(program, 'apos');

    // 8 vertex coordinate arrays
    var data = new Float32Array([
      0.5, 0.5, 0.5,//vertex 0
      -0.5, 0.5, 0.5,//vertex 1
      -0.5, -0.5, 0.5,//vertex 2
      0.5, -0.5, 0.5, // Vertex 3
      0.5, 0.5, -0.5, //vertex 4
      -0.5, 0.5, -0.5,//vertex 5
      -0.5, -0.5, -0.5,//vertex 6
      0.5, -0.5, -0.5, // Vertex 7
    ]);
    // Vertex index array
    var indexes = new Uint8Array([
      //The first four points correspond to the index value
      0, 1, 2, 3,//gl.LINE_LOOP mode draws a rectangular frame with four points
      //The last four vertices correspond to index values
      4, 5, 6, 7,//gl.LINE_LOOP mode draws a rectangular frame with four points
      //The corresponding index value of the corresponding point before and after
      0, 4, // two points draw a straight line
      1, 5,//two points draw a straight line
      2, 6,//two points draw a straight line
      3, 7//Two points draw a straight line
    ]);

    //Create a vertex buffer object
    var buffer = gl. createBuffer();
    // bind the buffer object
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    //The vertex array data data is passed into the buffer
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

    //Create index buffer object
    var indexesBuffer = gl. createBuffer();
    // bind the buffer object
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexesBuffer);
    //The index array indexes data is passed into the buffer
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexes, gl.STATIC_DRAW);

    //The data in the buffer is passed to the position variable apos according to certain rules
    gl.vertexAttribPointer(aposLocation, 3, gl.FLOAT, false, 0, 0);
    //Allow data transfer
    gl. enableVertexAttribArray(aposLocation);


    //LINE_LOOP mode draws the first four points
    gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 0);
    //LINE_LOOP mode draws four points starting from the fifth point
    gl.drawElements(gl.LINE_LOOP, 4, gl.UNSIGNED_BYTE, 4);
    //8 points after drawing in LINES mode
    gl. drawElements(gl. LINES, 8, gl. UNSIGNED_BYTE, 8);


    //declare initialization shader function
    function initShader(gl, vertexShaderSource, fragmentShaderSource) {
      var vertexShader = gl.createShader(gl.VERTEX_SHADER);
      var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl. shaderSource(vertexShader, vertexShaderSource);
      gl. shaderSource(fragmentShader, fragmentShaderSource);
      gl. compileShader(vertexShader);
      gl. compileShader(fragmentShader);
      var program = gl. createProgram();
      gl. attachShader(program, vertexShader);
      gl. attachShader(program, fragmentShader);
      gl. linkProgram(program);
      gl. useProgram(program);
      return program;
    }
  </script>
</body>

</html>

Impression