This is the 18th day of my participation in the August Challenge

WebGL Usage Guide (5) Drawing triangles

You probably know. The basic unit of a THREE-DIMENSIONAL model is a triangle. No matter how complex the shape of a three-dimensional model is, its basic components are all triangles, but a complex model is made up of more triangles. Therefore, how to draw triangles is very important for rendering 3d models.

Function of buffer

For graphics, which may be composed of multiple points, all vertices in a graph need to be passed to the vertex shader before the graph can be changed. Webgl provides a convenient mechanism — buffer objects, which can pass multiple vertex data to the shader at once. A buffer object is an area of the WebGL system that can be filled with a large amount of vertex data at once and stored there for use by vertex shaders.

1. Create/delete a buffer object

gl.createBuffer(); // Create buffer object gl.deleteBuffer(buffer); // Remove the buffer object copy code represented by the parameter bufferCopy the code

2. Bind the buffer object to the target in the WebGL system

gl.bindBuffer(target, buffer); // Allows the buffer object represented by buffer to be used and bound to the target represented by target. // The target argument can be one of the following: gl.array_buffer specifies the data in the buffer object that contains the vertexCopy the code

3. Write data to the buffer

gl.bufferData(target, data, usage); // Create storage space, Write data to the buffer object bound to target data //target gl.array_buffer or gl.element_array_buffer //data Write data to the buffer object //usage Represents how the program will use data stored in a buffer object. Gl. STATIC_DRAW means that data will be written to the buffer object only once, but many times. Gl. STREAM_DRAW means that data will be written to the buffer object only once, and then a number of times. And draw multiple copies of the codeCopy the code

4. Assign the buffer object to the attribute variable

gl.vertexAttribPointer(location,size,type,normalized,stride,offset); // The buffer object bound to gl.array_buffer is assigned to the attribute variable specified by location. //location Specifies the location where the attribute variable is allocated. Size specifies the number of components for each vertex in the buffer (1-4). Type Specifies the data format with one of the following types: Gl.nusigned_byte Unsigned bytes, Uint8Array gl.SHORT Uint16Array gl.UNSIGNED_SHORT Unsigned integer type,Uint16Array gl.INT UNSIGEND_INT Unsigned integer type, Uint32Array gl.FLOAT Float32Array normalized Number of bytes between two neighboring vertices. The default value is 0. Offset Specifies the offset in the buffer object. That is, where the attribute variable is stored from in the buffer, and offset is set to 0 if it is stored from the starting position to copy the codeCopy the code

Next we use code to draw a triangle

<body> <canvas width="500" height="500" id="oCanvas"></canvas> <script type="notjs" id="vertex"> attribute vec2 a_position; attribute vec4 a_color; uniform vec2 screenSize; varying vec4 v_color; attribute float pointsize; Void main () {float x = a_position.x * 2.0 / screensize.x - 1.0; Float y = 1.0 - (a_position.y * 2.0 / screensize. y); float y = 1.0 - (a_position.y * 2.0 / screensize. y); gl_Position = vec4(x, y, 0, 1); gl_PointSize = pointsize; v_color = a_color; } </script> <script type="notjs" id="fragment"> precision mediump float; varying vec4 v_color; void main () { gl_FragColor = v_color; } </script> <script> var oCanvas = document.getElementById('oCanvas'); var gl = oCanvas.getContext('webgl'); if (! Gl) {alert(' browsers don't support webGL '); Function createShader(gl, type, source) {var shader = gl.createshader (type); gl.shaderSource(shader, source); gl.compileShader(shader); var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (success) { return shader; } console.log(gl.getShaderInfoLog(shader)); } var vetexStr = document.getElementById('vertex').innerText; var fragmentStr = document.getElementById('fragment').innerText; var vertexShader = createShader(gl, gl.VERTEX_SHADER, vetexStr); var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr); function createProgram(gl, vertexShader, fragmentShader) { var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); var success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { return program; } console.log(gl.getProgramInfoLog(shader)); } var program = createProgram(gl, vertexShader, fragmentShader); console.log(program); gl.useProgram(program); var a_position = gl.getAttribLocation(program, "a_position"); var pointsize = gl.getAttribLocation(program, "pointsize"); var screenSize = gl.getUniformLocation(program, 'screenSize'); var a_color = gl.getAttribLocation(program, "a_color"); gl.uniform2f(screenSize, oCanvas.width, oCanvas.height); gl.vertexAttrib4f(a_color, 1, 0, 1, 1); var positionBuffer = gl.createBuffer(); // Create buffer object gl.bindBuffer(gl.array_buffer, positionBuffer); Function bindEvent() {var points = []; oCanvas.onmousedown = function (e) { gl.clearColor(0, 1, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); var x = e.offsetX; var y = e.offsetY; var color = randomColor(); Points. Push (x, y, 10.0); If (points.length % 3 == 0) {// bind the buffer data // bind the buffer for the first argument // pass the data for the second argument (strongly typed languages require you to convert it with typed arrays if required) // The third parameter is drawn as gl.STATIC_DRAW, which means that the data in the buffer will not change frequently (webGL does some optimization based on this parameter). new Float32Array(points), gl.STATIC_DRAW); // Assign data to a variable // The first argument is which variable to assign data to // The second argument is the number of components that the variable has data // The third argument is the data type // The fourth argument is whether to normalize data if it is non-floating point data if set to true Numbers of numeric type bytes between -128 and 127 (BYTE) are passed between -1.0 and 1.0, numbers of numeric type bytes between 0 and 255 (UNSIGNED_BYTE) are converted between 0.0 and 1.0, and SHORT is converted between -1.0-1.0. If the value is false, the data entered by the user is processed. // The fifth argument is the number of bytes between two vertices, and the third argument is used only when the third argument is FLOAT (UNSIGNED_BYTE, SHORT, UNSIGNED_SHORT, INT, UNSIGNED_INT). So the number of bytes per vertex, Gl. vertexAttribPointer(a_position, 2, gl.float, 0) * Number of bytes between two vertices * Number of bytes per element // The sixth argument is the current variable from which data is taken from each vertex. false, 4 * 3, 0); gl.vertexAttribPointer(pointsize, 1, gl.FLOAT, false, 4 * 3, 4 * 2); / / enable the location data gl. EnableVertexAttribArray (a_position); gl.enableVertexAttribArray(pointsize); // TRIANGLES gl.drawarrays (TRIANGLES, gl.Triangles, 0, points.length / 3); } } } function randomColor() { var r = Math.random(); var g = Math.random(); var b = Math.random(); Var a = 0.5 + math.random () * 0.5; return { r, g, b, a } } bindEvent(); </script> </body> Copies the codeCopy the code

We can see that we have successfully used the code to draw a triangle by placing three arbitrary points on the canvas