primers

JavaScript WebGL base confusion after some optimization, then try to draw common two-dimensional faces.

Geometry in WebGL is ultimately made up of triangles, which is more appropriate to cut in.

Draw a triangle

Here is an example, based on drawing a line the main changes are:

  • The vertices

  • Drawing primitives

The vertices

A triangle has three vertices. In the basic puzzle point, I know that the coordinate system is the right hand coordinate system. I am used to describing the sequence of vertices from the center of the graph as the origin, from the first quadrant to the fourth quadrant.


let vertices = [

    0.5.0.5.0.0.// First quadrant

    -0.5.0.5.0.0.// Second quadrant

    -0.5, -0.5.0.0.// Third quadrant

]; / / triangle

Copy the code

Drawing primitives

So this time, using a face, the drawing mode in drawArrays is changed to Gl.Triangles. Take a look at some patterns of primitives.

  • Gl. POINTS: Draws a series of POINTS.

  • Gl.lines: Draws a series of separate line segments, with two points as endpoints and no connection between the segments. For example, if you have vertices A, B, C, D, E, and F, you get three line segments.

  • Gl.line_strip: Draws a series of line segments with the top point connecting the next.

  • Gl.line_loop: Draws a series of line segments, the top point connecting to the next point, and the last point connecting to the first point.

  • TRIANGLES: Using a series of TRIANGLES, using three points as vertices. For example, if there are six vertices A, B, C, D, E, and F, two triangles will be drawn: ABC and DEF.

  • Gl. TRIANGLE_STRIP: Used to draw triangles with shared sides. Starting with the second triangle, read one vertex at a time, and form a triangle using the previous two trailing vertices, and so on. For example, if there are six vertices A, B, C, D, E, F, four triangles will be drawn: ABC and BCD and CDE and DEF.

  • Gl. TRIANGLE_FAN: Draw triangles with shared edges. Starting with the second triangle, read one vertex at a time, and form a triangle using the first vertex and the last vertex before it, and so on. For example, if there are six vertices A, B, C, D, E, F, four triangles will be drawn: ABC and ACD and ADE and AEF.

Implementation process

Here is a visualization of the execution process of drawing triangles, combined with a look to help deepen understanding.

Hd processing

In the example above, there is obvious blur and jagging on an HD screen, but it is a little different from dealing with blur in a 2D context. The main difference is that WebGL requires viewPort methods to specify mapping transformations from standard devices to window coordinates. Details can be found in this article.

This is the HD example.


function WebGLHD(w = 300, h = 150) {

    const ratio = window.devicePixelRatio || 1;

    const canvas = document.createElement("canvas");

    const context = canvas.getContext("webgl");

    // Handle hd screen blur

    canvas.width = w * ratio; // Actual render pixels

    canvas.height = h * ratio; // Actual render pixels

    canvas.style.width = `${w}px`; // Control the display size

    canvas.style.height = `${h}px`; // Control the display size

    context.viewport(0.0, context.canvas.width, context.canvas.height);

}

Copy the code

Draw a rectangle

As mentioned above, geometry in WebGL is ultimately composed of triangles, which need to be decomposed into multiple triangles when drawing polygons.

Here is an example where a rectangle can be divided into two triangles:


let vertices = [

0.5.0.5.0.0,

-0.5.0.5.0.0,

-0.5, -0.5.0.0.// The first triangle

-0.5, -0.5.0.0.0.5, -0.5.0.0.0.5.0.5.0.0.// The second triangle

]; / / rectangle

Copy the code

If one edge is found to be common, the buffer object can be indexed to reduce redundant data.

Index buffer object

The full name of an Index Buffer Object is Index Buffer Object (IBO), which uses indexes to reuse existing data.

Based on the square example above, the main changes are as follows:

  • data

  • The buffer

  • draw

data

Only four vertex positions are needed, and the public data is indexed instead.


const vertices = [

0.5.0.5.0.0.// first vertex

-0.5.0.5.0.0.// second vertex

-0.5, -0.5.0.0.// the third vertex

0.5, -0.5.0.0.// the fourth vertex

]; / / rectangle

Copy the code

The index data is related to the primitive drawing mode indicated above.

Using the TRIANGLES mode of Gl. TRIANGLES are independent, with the following indexed data:


const indexData = [

0.1.2.// The index of vertex 1, 2, and 3 in the corresponding vertex position data

0.2.3.// The index of vertex 1, 3, and 4 in the corresponding vertex position data

]

Copy the code

Construct a triangle using the two vertices at the end of the previous triangle when drawing mode is GL. TRIANGLE_STRIP:


const indexData = [

1.0.2.3 // Select * from index 1, 0, 2 to draw the first triangle, and then select * from index 0, 2, 3 to draw the second triangle

]

Copy the code

When drawing in gl.TRIANGLE_FAN, construct a triangle using the first vertex and the vertex at the end of the previous triangle, plus the newly read vertex:


const indexData = [

0.1.2.3 // Select * from index 0, 1, 2 to draw the first triangle, and then select * from index 0, 2, 3 to draw the second triangle

]

Copy the code

The buffer

The indexed data needs to be buffered to the corresponding variables before it can be used.


/** * buffer index data *@param {*} Gl WebGL context *@param {*} Data Index data */

function setIndexBuffers(gl, data) {

    // Create a blank buffer object

    const buffer = gl.createBuffer();

    // Bind the target

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);

    // WebGL does not support using JavaScript primitive array types directly

    const dataFormat = new Uint16Array(data);

    // Initialize the data store

    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, dataFormat, gl.STATIC_DRAW);

}

Copy the code

draw

The index buffer object is used and drawElements method is needed instead of drawArrays. This method takes a type parameter, which refers to the type of the index buffer data, with the following values:

  • gl.UNSIGNED_BYTE

  • gl.UNSIGNED_SHORT

The previous buffered-index data type is converted to Uint16Array, where gl.unsigned_short should be used.

The three methods are as follows:

The resources

Recently, I saw a work “Deli Lili’s Fantasy Paris”, in which the costumes of the characters are gorgeous and distinctive, and the scene architecture is exquisite.

The story expresses a positive attitude, but most of the people you meet in the plot are either rich or wealthy, which is a bit magical.