1#  Using WebGL to Draw Graphics
2
3## When to Use
4
5Web Graphic Library (WebGL) is used for rendering interactive 2D graphics. WebGL used in OpenHarmony is based on OpenGL for Embedded Systems (OpenGL ES). It can be used in the HTML5 **\<canvas>** element without using plug-ins and supports cross-platform. WebGL is programmed by JavaScript code. Its APIs can implement graphics rendering and acceleration by using GPU hardware provided by the user equipment. For more information, see [WebGL™](https://www.khronos.org/registry/webgl/specs/latest/1.0/).
6
7> **NOTE**
8>
9> WebGL can be used only in the JavaScript-compatible web-like development paradigm.
10
11## Basic Concepts
12
13### Shader program
14
15The shader program, also known as WebGL program, is a JavaScript object responsible for associating the shader with the buffer. A **WebGLProgram** object consists of two compiled WebGL shaders: a vertex shader and a fragment shader.
16
17###  Shader
18
19Shaders are instructions and data that run in a graphics card. In WebGL, shaders are written in the OpenGL Shading Language (GLSL).
20
21There are vertex shaders and fragment shaders. The interaction between vertex shaders and fragment shaders involves rasterization.
22
23- The vertex shader is mainly used to receive the coordinates of a point in a 3D space, convert the coordinates into coordinates in a 2D space, and output the coordinates.
24
25- The fragment shader is mainly used to output a color value for each pixel being processed.
26
27###  Rasterization
28
29Rasterization is the process of converting the coordinates in a 2D space output by the vertex shader into pixels to be processed and passing the pixels to the fragment shader.
30
31### Frame buffer
32
33The frame buffer provides an alternative rendering target for the drawing buffer. They are a collection of colors, letters, depths, and template buffers and are usually used to render images.
34
35###  Texture
36
37A texture is an image that can be applied to the surface of a 3D model. Textures in WebGL have many properties, including width, height, format, and type. When using a texture, load it into WebGL and bind it to a texture unit.
38
39
40## Variables and APIs
41
42### Variables
43
44| Type        | Web IDL Type        | Description                                                        |
45| ------------ | -------------------- | ------------------------------------------------------------ |
46| GLenum     | unsigned long     | Enum.       |
47| GLboolean  | boolean            | Boolean, either **true** or **false**.|
48| GLbitfield | unsigned long      | Unsigned integer. Multiple bit flags can be contained, and each bit flag represents a specific option.|
49| GLbyte     | byte               | Signed integer represented by 2's complement of 8 bits (one byte).               |
50| GLshort    | short              | Signed integer represented by 2's complement of 16 bits.                            |
51| GLint      | long               | Signed integer represented by 2's complement of 32 bits.                          |
52| GLsizei    | long               | Size, for example, the width and height of the drawing buffer.     |
53| GLintptr   | long long          | A special type used to represent a pointer. It is usually used to specify the offset of a buffer object.      |
54| GLsizeiptr | long long          | A special type used to represent a pointer. It is usually used to specify the size of a buffer object.        |
55| GLubyte    | octet              | Unsigned integer represented by 2's complement of 8 bits (one byte).                |
56| GLushort   | unsigned short     | Unsigned integer represented by 2's complement of 16 bits.                         |
57| GLuint    | unsigned short     | Signed integer represented by 2's complement of 32 bits.                       |
58| GLfloat   | unrestricted float | 32-bit IEEE floating point number.                            |
59| GLclampf   | unrestricted float | 32-bit IEEE floating point number.                                     |
60
61### Available APIs
62
63| API                                                      | Description                                                  |
64| ------------------------------------------------------------ | ------------------------------------------------------ |
65| canvas.getContext                                            | Obtains the canvas context.                                |
66| webgl.createBuffer(): WebGLBuffer \| null                    | Creates and initializes a WebGL buffer.                         |
67| webgl.bindBuffer(target: GLenum, buffer: WebGLBuffer \| null): void | Binds a WebGL buffer to the target.                     |
68| webgl.bufferData(target: GLenum, srcData: ArrayBufferView, usage: GLenum, srcOffset: GLuint, length?: GLuint): void | Creates and initializes the WebGL buffer's data store.                       |
69| webgl.getAttribLocation(program: WebGLProgram, name: string): GLint | Obtains the address of the **attribute** variable in the shader from the given WebGL program.|
70| webgl.vertexAttribPointer(index GLuint, size: GLint, type: GLenum, normalized: GLboolean, stride: GLsizei, offset: GLintptr): void | Assigns a **Buffer** object to a variable.                              |
71| webgl.enableVertexAttribArray(index: GLuint): void           | Connects a variable to the **Buffer** object allocated to it.                      |
72| webgl.clearColor(red: GLclampf, green:GLclampf, blue: GLclampf, alpha: GLclampf): void | Clears the specified color on the canvas.                        |
73| webgl.clear(mask: GLbitfield): void                          | Clears the canvas.                                  |
74| webgl.drawArrays(mode: GLenum, first:;GLint, count: GLsizei): void | Draws data.                                        |
75| webgl.flush(): void                                          | Flushes data to the GPU and clears the buffer.                           |
76| webgl.createProgram(): WebGLProgram \| null                  | Creates a **WebGLProgram** object.                                  |
77
78## How to Develop
79
80 The following uses a color square as an example to describe how to draw a 2D graphic using WebGL.
81
821. Before using WebGL for 3D rendering, create a **\<canvas>** element. The following code snippet creates a **\<canvas>** element and sets an onclick event handler to initialize the WebGL context.
83
84   ```hml
85    <div class="container">
86        <canvas ref="canvas1" style="width : 400px; height : 400px; background-color : lightyellow;"></canvas>
87        <button class="btn-button" onclick="BtnColorTriangle">BtnColorTriangle</button>
88    </div>
89   ```
90
912. Set the WebGL context.
92
93   - Call the **main()** function in the JavaScript code after loading to set the WebGL context and start rendering.
94
95   - Call the **getContext** function, with the **webgl** parameter passed in, to obtain the WebGL rendering context. If the browser does not support WebGL, **null** is returned. If the WebGL context is initialized, the variable **'gl'** is used to reference the context.
96
97   ```js
98   function main() {
99     const canvas = document.querySelector("#glcanvas");
100     // Initialize the WebGL context.
101     const gl = canvas.getContext("webgl");
102
103     // Check the support for WebGL.
104     if (!gl) {
105       alert("Your browser, operating system, or hardware may not support WebGL.");
106       return;
107     }
108     // Use completely opaque black to clear all images.
109     gl.clearColor(0.0, 0.0, 0.0, 1.0);
110     // Clear the buffer with the color specified above.
111     gl.clear(gl.COLOR_BUFFER_BIT);
112   }
113   ```
1143. Define the vertex shader.
115
116   The vertex shader needs to perform the necessary transformation (for example, adjustment or calculation) on the vertex coordinates, saves the new vertices in a special variable provided by GLSL, and returns the variable.
117
118   ```js
119   const vsSource = `
120       attribute vec4 aVertexPosition;
121       uniform mat4 uModelViewMatrix;
122       uniform mat4 uProjectionMatrix;
123       void main() {
124         gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
125       }
126     `;
127   ```
128
1294. Define the fragment shader.
130
131   After the vertex shader processes the vertices, the fragment shader is called once by each pixel to be drawn.
132
133   ```js
134   const fsSource = `
135       void main() {
136         gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
137       }
138    `;
139   ```
1405. Pass the shader to WebGL.
141
142   Pass the vertex shader and fragment shader defined to WebGL and compile them together.
143
144   The following code uses **loadShader()** to transfer the type and source for the shader. In this example, two shaders are created and attached to a shader program. If the compilation or linking fails, an alert is displayed.
145
146   ```js
147   // Initialize the shader program so that WebGL knows how to draw data.
148   function initShaderProgram(gl, vsSource, fsSource) {
149     const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
150     const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
151     // Create a shader program.
152     const shaderProgram = gl.createProgram();
153     gl.attachShader(shaderProgram, vertexShader);
154     gl.attachShader(shaderProgram, fragmentShader);
155     gl.linkProgram(shaderProgram);
156     // An alert is displayed if the creation fails.
157     if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
158       alert(
159         "Unable to initialize the shader program: "+
160        gl.getProgramInfoLog(shaderProgram),
161       );
162       return null;
163     }
164     return shaderProgram;
165   }
166   // Create a shader of the specified type, upload the source code, and compile the source code.
167   function loadShader(gl, type, source) {
168     const shader = gl.createShader(type);
169     // Send the resource to the shader object.
170     gl.shaderSource(shader, source);
171     // Compile the shader program.
172     gl.compileShader(shader);
173     // Check whether the compilation is successful.
174     if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
175       alert(
176      "Error occurred when compiling the shader: "+ gl.getShaderInfoLog (shader),
177       );
178       gl.deleteShader(shader);
179       return null;
180     }
181     return shader;
182   }
183   ```
1846. Find the input location assigned by WebGL.
185
186   - After creating the shader program, find the input location allocated by WebGL. There is one property and two Uniforms.
187
188   - The property value is assigned by the buffer. For each iteration of the vertex shader, a new value is assigned.
189
190   - Uniforms are similar to JavaScript global variables. They use the same value in all iterations of the shader. Because the property location is specific to a shader program, they can be stored together for easy delivery.
191
192   ```js
193   const programInfo = {
194     program: shaderProgram,
195     attribLocations: {
196       vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
197     },
198     uniformLocations: {
199       projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
200       modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
201     },
202   };
203   ```
204
2057. Create a buffer object.
206
207   - Before drawing the square, create a buffer to store its vertices.
208
209   - Call the **createBuffer()** function of **gl** to obtain a buffer object and store it in the vertex buffer. Then call the **bindBuffer()** function to bind the context.
210
211   - Create a JavaScript array to record each vertex of the square, convert the JavaScript array into an array of the WebGL floating-point type, and pass the latter to the **bufferData()** function of **gl** to establish the vertices of the object.
212
213   ```js
214   function initBuffers(gl) {
215     const positionBuffer = initPositionBuffer(gl);
216     return {
217       position: positionBuffer,
218     };
219   }
220   function initPositionBuffer(gl) {
221     // Create a position buffer for the square.
222     const positionBuffer = gl.createBuffer();
223     // Bind the position buffer to the application buffer.
224     gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
225     // Create an array to hold the vertices of the square.
226     const positions = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0];
227     // Pass the position array to WebGL.
228     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
229     return positionBuffer;
230   }
231   export { initBuffers };
232   ```
233
2348. Start render.
235
236   - Erase the canvas with the background color, and then build a camera perspective projection matrix. Set the view angle to 45 degrees and set an aspect ratio suitable for the actual image. Specify that objects within the range of 0.1 to 100 units from the camera are visible.
237
238   - Load a specific position and place the square in a position six units away from the camera. Then, bind the square's vertex buffer to the context, configure the buffer, and call the **drawArrays()** method to draw the square.
239
240   ```js
241   function drawScene(gl, programInfo, buffers) {
242     gl.clearColor(0.0, 0.0, 0.0, 1.0);
243     gl.clearDepth(1.0); // Clear all content.
244     gl.depthFunc(gl.LEQUAL);
245     // Clear the canvas.
246      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
247     // Create a perspective projection matrix to simulate perspective deformation in the camera.
248     const fieldOfView = (45 * Math.PI) / 180;
249     const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
250     const zNear = 0.1;
251     const zFar = 100.0;
252     const projectionMatrix = mat4.create();
253     mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
254     // Set the drawing position to the center of the scene.
255     const modelViewMatrix = mat4.create();
256     // Start to draw the square.
257     mat4.translate(
258       modelViewMatrix, // Target matrix.
259       modelViewMatrix, // Matrix to be converted.
260       [-0.0, 0.0, -6.0],
261     );
262     {
263       const numComponents = 2;
264       const type = gl.FLOAT;
265       const normalize = false;
266       const stride = 0; // Number of bytes required from a group of values to the next group of values.
267       const offset = 0;
268       gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
269       gl.vertexAttribPointer(
270         programInfo.attribLocations.vertexPosition,
271         numComponents,
272         type,
273         normalize,
274         stride,
275         offset,
276       );
277       gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
278     }
279     gl.useProgram(programInfo.program);
280     gl.uniformMatrix4fv(
281       programInfo.uniformLocations.projectionMatrix,
282       false,
283       projectionMatrix,
284     );
285     gl.uniformMatrix4fv(
286       programInfo.uniformLocations.modelViewMatrix,
287       false,
288       modelViewMatrix,
289     );
290     {
291       const offset = 0;
292       const vertexCount = 4;
293       gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
294     }
295   }
296   // Tell WebGL how to pull the position buffer to the vertexPosition attribute.
297   function setPositionAttribute(gl, buffers, programInfo) {
298     const numComponents = 2;
299     const type = gl.FLOAT;
300     const normalize = false;
301     const stride = 0; // Number of bytes required from a group of values to the next group of values.
302     const offset = 0;
303     gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
304     gl.vertexAttribPointer(
305       programInfo.attribLocations.vertexPosition,
306       numComponents,
307       type,
308       normalize,
309       stride,
310       offset,
311     );
312     gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
313   }
314   export { drawScene };
315   ```
316
317The following figure shows the implementation effect.
318
319![Implementation effect](figures/square.png)
320