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