Drawing a triangle is one more step than drawing a point. The triangle needs to create a buffer. There are several ways to draw a triangle. The code for the three drawing methods is almost the same. Only the type in drawArrays(type,start,count) is different when rendering.

The following examples use the GLSL knowledge.

Gl. createBuffer: Creates a buffer. Gl.bindbuffer: Binds a buffer object to the current buffer. Gl. bufferData: Copies data to the buffer. Gl. EnableVertexAttribArray: enable vertex attribute. Gl. vertexAttribPointer: Sets the way the vertex property reads data from the buffer.Copy the code
  • Vertex shader code
<script id="vertexShader" type="x-shader/x-vertex">
  //attribute declares the vec4 type variable apos
  attribute vec4 apos;
  void main() {
    // Vertex coordinates apOS is assigned to the built-in variable gl_Position
    // Process data vertex by vertex
    gl_Position = apos;
  }
</script>
Copy the code
  • Chip shader code
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
    // Process the data bit by bit with all pixels set to red
    gl_FragColor = vec4(1.0.0.0.0.0.1.0);
  }
</script>
Copy the code
  • Javascript code, mainly composed of the following four parts of the code
    • To obtainWebGLcontext
    // Get the canvas canvas with the getElementById() method
    const canvas = document.getElementById('webgl');
    // Get the WebGL context using the getContext() method
    const gl = canvas.getContext('webgl');
    // Initialize the shader
    const program = initShader(gl);
    // Initialize the cache
    const count = initBuffer(gl);
    render(gl, program, count);
    Copy the code
    • Declare the initialization shader function
    // Declare the initialization shader function
    function initShader(gl) {
        // Vertex shader source code
        const vertexShaderSource = document.getElementById('vertexShader').innerText;
        // Chip shader source code
        const fragmentShaderSource = document.getElementById('fragmentShader').innerText;
        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(vertexShader, vertexShaderSource);
        gl.shaderSource(fragmentShader, fragmentShaderSource);
        gl.compileShader(vertexShader);
        gl.compileShader(fragmentShader);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);
        return program;
    }
    Copy the code
    • Initialize cached data
    // Initialize buffered data
    function initBuffer(gl) {
        // Array constructor Float32Array creates an array of vertices
        const data = new Float32Array([-0.5.0.5,
        -0.5, -0.5.0.5.0.5,]);// Create a buffer object
        var buffer = gl.createBuffer();
        // Bind buffer objects to activate buffer
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        // The vertex array data is passed into the buffer
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
        return data.length;
    }
    Copy the code
    • Apply colours to a drawing
    function render(gl, program, count) {
        // Get the vertex shader's location variable apos, that is, aposLocation points to the apOS variable.
        const aposLocation = gl.getAttribLocation(program, 'apos');
    
        // The data in the buffer is passed to the position variable APOS according to certain rules
        gl.vertexAttribPointer(aposLocation, 2, gl.FLOAT, false.0.0);
        // Allow data transfer
        gl.enableVertexAttribArray(aposLocation);
        // Set the clear color to black.
        gl.clearColor(0.0.0.1.0);
        / / clear screen
        gl.clear(gl.COLOR_BUFFER_BIT);
        // Start drawing
        gl.drawArrays(gl.TRIANGLES, 0, count);
    }
    Copy the code

1, the conventional way

gl.drawArrays(gl.TRIANGLES, 0.3);
Copy the code

2. Triangle belt

Number of triangles drawn = number of vertices – 2

 gl.drawArrays(gl.TRIANGLE_STRIP, 0.3);
Copy the code

3. Triangle fan

Number of triangles drawn = number of vertices – 2

 gl.drawArrays(gl.TRIANGLE_FAN, 0.3);
Copy the code

4. Draw triangles dynamically

The code in the shader is almost identical to the code for dynamically drawing points. Just one more color interpolation process.

  • Vertex shader code
<script type="shader-source" id="vertexShader">
    // Float is set to medium precision
    precision mediump float;
    // Accept the coordinates (X, Y) of the point passed by JavaScript.
    attribute vec2 a_Position;
    attribute vec4 a_Color;
    varying vec4 v_Color;
    void main(){
        // Final vertex coordinates.
        gl_Position = vec4(a_Position, 0.0.1.0);
        // Perform color interpolation calculations
        v_Color = a_Color;
    }
</script>
Copy the code
  • Chip shader code
<script type="shader-source" id="fragmentShader">
    // Float is set to medium precision
    precision mediump float;
    // To receive interpolated vertex colors from the vertex shader.
    varying vec4 v_Color;
    void main(){
        // The final color of the dot.
        gl_FragColor =  v_Color;
    }
</script>
Copy the code
  • Javascript code
    • WebGLContext retrieval
    // Get the canvas canvas with the getElementById() method
    const canvas = document.getElementById('webgl');
    // Set the canvas size to full screen
    // Note that setting the canvas size must be called before fetching the WebGL context
    resizeCanvas(canvas);
    // Get the WebGL context using the getContext() method
    const gl = canvas.getContext('webgl');
    Copy the code
    • canvasThe size is dynamically set
    // Set the canvas size
    function resizeCanvas(canvas, width, height) {
        if(canvas.width ! == width) { canvas.width = width ? width :window.innerWidth;
        }
        if(canvas.height ! == height) { canvas.height = height ? height :window.innerHeight; }}Copy the code
    • Variable assignment processing in the shader
    function assignValue(gl,program){
        let a_Position = gl.getAttribLocation(program, 'a_Position');
        let a_Color = gl.getAttribLocation(program, 'a_Color');
        gl.enableVertexAttribArray(a_Position);
        gl.enableVertexAttribArray(a_Color);
        let buffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        // Pass the data in the buffer to a_Position according to certain rules, which means that two floating-point data (floating-point data, 4 bytes) are fetched from the cache. The first line of cache is 4*6 bytes, and the offset is 0
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false.4*6.0);
        gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false.4*6.8);
    }
    Copy the code
    • Click event listening
    const positions = [];
    function initClick() {  
        canvas.addEventListener("click".e= > {
            const color = randomColor();
            constposition = coordTransform(e.pageX, e.pageY) positions.push(... position, ... Object.values(color));// If the vertex information is an integer multiple of 18, i.e., 3 vertices, draw because the triangle consists of three vertices, each of which consists of six elements.
            if (positions.length % 18= =0) {
                // gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); render(gl); }})}// Random generation of color values
    const random = Math.random;
    function randomColor() {
        return {
            r: random(),
            g: random(),
            b: random(),
            a: random()
        };
    }
    Copy the code
    • Declare the initialization shader function
    // Declare the initialization shader function
    function initShader(gl) {
        // Vertex shader source code
        const vertexShaderSource = document.getElementById('vertexShader').innerText;
        // Chip shader source code
        const fragmentShaderSource = document.getElementById('fragmentShader').innerText;
        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(vertexShader, vertexShaderSource);
        gl.shaderSource(fragmentShader, fragmentShaderSource);
        gl.compileShader(vertexShader);
        gl.compileShader(fragmentShader);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);
        return program;
    }
    Copy the code
    • Screen coordinates are converted to the coordinates of the clipping coordinate system (vertex shader)
    // Convert screen coordinates to clipping coordinates (coordinates in shaders)
    const { width, height } = canvas;
    function coordTransform(x, y) {
        // Convert the canvas coordinate value to the range of [-1.0, 1.0].
        const posisionX = 2 * x / width - 1;
        // Canvas's Y coordinate is opposite to the clipped coordinate.
        const positionY = -(2 * y / height - 1);
        return [posisionX, positionY];
    }
    Copy the code
    • WebGLApply colours to a drawing
    function render(gl) {
        // Set the clear color to black.
        gl.clearColor(0.0.0.1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        if (positions.length > 0) {
            gl.drawArrays(gl.TRIANGLES, 0, positions.length / 6); }}// Create a shader program
    const program = initShader(gl);
    constassignValue(gl,program)
    initClick();
    render(gl);
    Copy the code

reference

WebGL Zero Basic Tutorial (Guo Longbang); Introduction to WebGL and Practice WebGL official documentation