This article is collated from Div Man in concave-Convex 2022 technology share, briefly introduces the process of WebGL drawing a basic graph, hope that after you understand, when using 3D rendering library can be less confused.

Four commonly used page drawing tools

For h5 page graphics, we mostly talk about these four tools: HTML + CSS, SVG, Canvas2D, webGL.

HTML + CSS is the most common drawing tool, using CSS drawing is the same as writing page layout at ordinary times, when making charts, we can use CSS to define the style of the chart, the other, is according to the different data, to add different attributes to the elements. Such development is very friendly for scenarios with simple chart elements and few data nodes. Not only do you reduce the number of tools you need to develop, but you don’t have to introduce redundant code bases. However, more and more graphics need to be drawn at any time, CSS code is becoming more and more complex, and CSS has no logical semantics, the code will become difficult to read and maintain.

SVG is a scalable vector graphics, which is closely combined with HTML and CSS. SVG can be used as SRC for IMG, and CSS can be used to manipulate SVG attributes. SVG and HTML are both text markup languages. SVG has more support for non-linear graphics than HTML, including arcs, Bezier curves, etc. SVG also supports an isoreuse class syntax, which allows it to draw a lot of graphics without leaving the code readable. However, SVG has some drawbacks. Because a graph is an element node. When there is a lot of data, the overhead of layout and rendering calculations caused by page refreshes can be very high. Also, full SVG puts structure, style, and reuse logic together, making it less neat than HTML + CSS + JS.

Canvas2D is the 2D drawing context of Canvas, which provides a series of methods for modifying and drawing images in the Canvas area. Compared with the former two out of the box, many graphics and colors of canvas2D need to be realized and encapsulated by themselves, making it much more difficult to use this tool. But if you do the basics right, you’ll have a drawing tool that completely covers the first two tools and is easy to extend.

WebGL is also the drawing context of Canvas and the Web implementation of OpengL ES. The biggest feature is the lower level, which can directly use the parallelism capability of GPU. It has a high performance advantage when dealing with a very large number of graphics, pixel-level processing and 3D object scenes.

The choice of four tools

When we get a drawing requirement, we should first see if the requirement is relatively small and simple. If so, you can simply choose CSS for rapid development. SVG can also be used quickly if the graphics are simple but large, or if the graphics have some curving requirements. Choose Canvas2D if the structure between shapes is complex and the number is large. When graphics are of a certain magnitude, or require processing of every pixel, or require a lot of 3D presentation, we use WebGL

Webgl hello world

Webgl’s Hello World is not one or two lines of code like other tools, but more than forty. Although this string of code has corresponding encapsulation methods in various 3D rendering libraries, we hardly need to write it by hand, but learning this string of code can give us a basic understanding of the WebGL drawing process.

There are five steps in WebGL drawing:

  1. Create a WebGL drawing context
  2. Create shader programming, associated to gl context (parallel with step 3)
  3. Create the data, put it into the buffer, and associate the buffer with gl (parallel with step 2)
  4. The GPU loads the data in the cache
  5. Drawing graphics

Create a Webgl context

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
Copy the code

Create shader program

const program = gl.createProgram();
gl.attachShader(program, /* A shader (vertexShader below)*/);
gl.linkProgram(program);
gl.useProgram(program);
Copy the code

A shader is a program for the GPU to run. We use glCreateProgram to create an empty program object, and then use glAttachShader to fill this program object with the compiled shader code. What a shader is and how it’s compiled will come later, but you can think of it as compiled code for a function. After putting several of these compiled functions into a program object, the GPU executes the program object, taking the pixel information as an input and executing the functions in the program object in turn.

After filling in the shader code, call glLinkProgram to associate the program with the GL context and use glUseProgram to enable the program.

Next, take a look at the shader code.

const vertex = ` attribute vec2 position; Void main() {gl_Position = vec4(position, 1.0, 1.0); } `;
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
Copy the code

First we define a variable vertex and assign it a string of code in another language format. This string is GLSL code, which is very similar to C code. The code receives an incoming two-dimensional vector position and sets the global variable gl_Position in its execution environment to a four-dimensional vector whose first two dimensional components are the incoming two-dimensional vectors.

Then create a shader using glCreateShader. The VERTEX_SHADER constant indicates that the shader is a vertex shader. The corresponding vertex shader is a slice shader, and the vertex shader is used to determine the position of the point. The slice shader processes all the positions in the graph composed of vertices one by one, such as drawing a straight line with two points determined by the vertex shader, and the line drawn by the slice shader after determining the positions of the two points.

After we create an empty vertexShader object, vertexShader, we can use glShaderSource to put the previous string code into the vertexShader object and then use glCompileShader to compile this code into an executable. This process is similar to the c compilation process.

gl.attachShader(program, /* A shader (vertexShader below)*/);
gl.attachShader(program, vertexShader);
Copy the code

Once you’ve done that, go back up there to comment and associate the shader object with the program object. Of course, you also have to write a fragment shader and use the same procedure to attach a fragment shader to the program object.

Buffer the data

const points = new Float32Array([-1, -1.0.1.1, -1]);
const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
Copy the code

After the previous steps, we now have a program object loaded with shader code that is enabled in the GL drawing context. Next, we need to define the data for this program.

In the vertex shader section, the code accepts an incoming two-dimensional vector, which is what we will now define. The first step is to define a typed array and initialize it with six numbers, which are then divided into three groups by the drawing program into three vertex shader calls. In addition, the purpose of using typed arrays is to optimize performance and make the data take up less space in case of large amounts of data.

Once you have the data, call glCreateBuffer to create a buffer object, use glBindBuffer to associate this object with the GL drawing context, and finally call glBufferData to put the points data into the buffer.

The GPU loads the data in the cache

const vPosition = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false.0.0);
gl.enableVertexAttribArray(vPosition);
Copy the code

In this step, we call glGetAttribLocation to get the position variable in the program object, glVertexAttribPointer to set the length to 2, set the type to glFLOAT, Using glEnableVertexAttribArray enable this variable

Drawing graphics

gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
Copy the code

At the last step, just clear the color buffer with glClear and draw with glDrawArrays. Using Gl. POINTS allows the shader to say what TRIANGLES are drawn using a third point. Say, Using Gl. POINTS allows the shader to say what TRIANGLES are drawn using a third point

This completes a Hello World for WebGL, and the triangle above is the output image of the 40 lines of code.

conclusion

This program is encapsulated in three.js and other 3D frameworks and tool libraries. It is relatively convenient to draw webGL through those libraries, but if you do not know the most basic operation of these libraries, it is easy to get involved in problems. So hopefully this article will increase your understanding of the underlying aspects of Web 3D and provide you with some help in learning these 3D toolkits.

The resources

GPU and Rendering Pipelines: How to draw the simplest geometry in WebGL?