WebGL initialization shader

Table of Contents

Preface

7 steps to initialize shaders

Create a shader object (gl.createShader())

gl.createShader() specification

gl.deleteShader() specification

Code specifying the shader object (gl.shaderSource())

gl.shaderSource() specification

Compile shader (gl.compileShader())

gl.compileShader() specification? Edit

gl.getShaderParameter() specification

gl.getShaderInfoLog() specification

Create program object (gl.createProgram())

gl.createProgram() specification

Assign a shader object to a program object (gl.attachShader())

gl.attachShader() specification

gl.detachShader() specification

LinkProgram object (gl.linkProgram())

gl.getProgramPara-meters() specification

gl.getProgramInfoLog() Specification

Tell the WebGL system which program object to use (gl.useProgram())

gl.usePorgram() specification

Internal flow of initShaders() function

initShaders() function

createProgram() function

loadShader() function


Foreword

This chapter will study the auxiliary function initShaders() that has been used before. All previous programs have used this function, which hides the details of building and initializing the shader. But if you really want to know how the WebGL native API compiles GLSL ES code in the form of a string into a shader program running in the graphics card, then the content of this section will greatly satisfy your curiosity.

7 steps to initialize a shader

The initShaders() function is used to compile GLSL ES code, create and initialize shaders for use by WebGL. Specifically, it is divided into the following 7 steps:

1. Create a shader object (gl.createShader()).

2. Fill the shader object with the source code of the shader program (gl.shaderSource()).

3. Compile the shader (gl.compileShader()).

4. Create a program object (gl.createProgram()).

5.. Assign a shader to the program object (gl.attachShader()).

6. Link program object (gl.linkProgram()).

7. Use the program object (gl.useProgram()).

Although each step seems relatively simple, when put together it becomes complicated, so we will discuss them one by one. First of all, you need to know that there are two kinds of objects here: shader object (shader object) and program object (program object).

Shader Object

A shader object manages a vertex shader or a fragment shader. Every shader has a shader object.

Program Object

A program object is a container that manages shader objects. In WebGL, a program object must contain a vertex shader and a fragment shader.

Relationship diagram between shader objects and program objects

Let’s discuss the above 7 steps one by one.

Create shader object (gl.createShader())

All shader objects must be created by calling gl.createShader().

gl.createShader() specification

The gl.createShader() function creates a vertex shader or fragment shader based on the passed parameters. If this shader is no longer needed, the shader can be deleted using the gl.deleteShader() function.

gl.deleteShader() specification

Note that if the shader object is still used ( That is to say, the gl.attachShader() function has been used to attach it to the program object (we will discuss this function soon), then gl.deleteShader() will not delete the shader immediately, but will wait until the program object is no longer Remove the shader only after using it again.

Specify the code of the shader object (gl.shaderSource())

Specify GLSL ES source code to the shader via the gl.shaderSource() function. In JavaScript programs, source code is stored in the form of strings

gl.shaderSource() specification

Compile Shader (gl.compileShader())

After passing the source code to the shader object, it needs to be compiled before it can be used. The GLSL ES language is different from JavaScript but closer to C or C++. It needs to be compiled into a binary executable format before use. The WebGL system actually uses this executable format. Compile using gl.compileShader() function. Note that if you replace the old code in the shader with the new code by calling gl.shaderSource(), the executable part compiled with the old code in the WebGL system will not be automatically replaced. You need to manually Recompile.

gl.compileShader() specification

Compilation errors will occur if there are errors in the shader source code when the gl.compileShader() function is called. The gl.getShaderParameter() function can be called to check the status of the shader.

gl.getShaderParameter() specification

Call gl.getShaderParameter() and pass the parameter pname Specify gl.COMPILE_STATUS to check whether the shader compilation is successful.

If compilation fails, gl.getShaderParameter() will return false, and the WebGL system will write the specific content of the compilation error to the shader’s information log (information log), which we can obtain through gl.getShaderInfoLog().

gl.getShaderInfoLog() specification

Although the specific format of the log information depends on the browser’s implementation of WebGL, the error information given by most WebGL systems will include the line number of the code error line. For example, if you try to compile a shader like this:

There is an error in line 2 of the code (it should be gl_ instead of gl.), the compilation error message given by the Chrome browser is shown in Figure 9.11 (cuon-utils.js prints the error message string on the console):

It can be seen that the error message tells us: the variable gl in line 2 is not defined.

cuon-utils.js:88 means that this error was detected in line 88 of the JavaScript file cuon-utils.js, where the initShaders() function is defined, which calls the gl.getShaderInfolog() function.

Create program object (gl.createProgram())

As mentioned before, the program object contains the vertex shader and the fragment shader, and gl.createProgram() can be called to create the program object. In fact, before using the program object, the first parameter of the gl.getAttribLocation() function and gl.getUniformLocation() function was this program object.

gl.createProgram() specification

Similarly, a program object can be deleted using gl.deleteProgram() function.

Once the program object is created, it needs to be Attached are two shaders.

Assign a shader object to the program object (gl.attachShader())

For a WebGL system to run, it must have two shaders: a vertex shader and a fragment shader. These two shaders can be assigned to a program object using the gl.attachShader() function.

gl.attachShader() specification

Shaders do not have to be assigned code or compiled before being attached to a program object (that is, it is possible to attach an empty shader to a program object). Similarly, a shader assigned to a program object can be deallocated using the gl.detachShader() function.

gl.detachShader() specification

After allocating two shader objects to the program object, you also need to connect the shaders (vertex shader and fragment). Use the gl.linkProgram() function to perform this step.

The program object performs shader connection operations to ensure that: (1) the varying variables of the vertex shader and the fragment shader have the same name and type, and correspond one to one; (2) the vertex shader assigns each varying variable The value; (3) Uniform variables with the same name in the vertex shader and fragment shader are also of the same type (no one-to-one correspondence is required, that is, some uniform variables can appear in one shader but not in the other); (4) The number of attribute variables, uniform variables and varying variables in the shader does not exceed the upper limit of the shader, etc.

After the shader is connected, you should check whether the connection was successful. This is achieved by calling the gl.getProgramPara-meters() function.

gl.getProgramPara-meters() specification

If the program has successfully connected, we have a binary executable module for use by the WebGL system. If the connection fails, you can also get the connection error information from the information log by calling gl.getProgramInfoLog().

gl.getProgramInfoLog() specification

Inform the WebGL system of the program object used (gl.useProgram())

Finally, you tell the WebGL system which program object to use when drawing by calling gl.usePorgram().

gl.usePorgram() specification

The existence of this function makes WebGL a powerful The characteristic is to prepare multiple program objects before drawing, and then switch the program objects as needed during drawing.

In this way, the task of creating and initializing the shader is completed. As you can see, the initShaders() function hides a lot of details that we can safely use to create and initialize shaders without having to think about these details. Essentially, after this function executes successfully, the vertex shader and fragment shader are already in place, and you only need to call gl.drawArrays() or gl.drawElements() to get the entire WebGL system running.

Now that you have a good understanding of the many WebGL native API functions mentioned above, let’s take a look at the internal process of the initShaders() function in cuon-utils.js.

Internal process of initShaders() function

The initShaders() function will call the createProgram() function, which is responsible for creating a connected program object; the createProgram() function will call the loadShader() function, which is responsible for creating a compiled shader object; these 3 Functions are defined in the cuon-utils.js file in turn. The initShaders() function is defined at the top of the file as follows

initShaders() function

function initShaders(gl, vshader, fshader) {
  //Create program object
  var program = createProgram(gl, vshader, fshader);
  if (!program) {
    console.log('Failed to create program');
    return false;
  }

  gl.useProgram(program);
  gl.program = program;

  return true;
}

The initShaders() function itself is very simple. It first calls the createProgram() function to create a connected program object, then tells the WebGL system to use this program object, and finally sets the program object to the program attribute of the gl object.

createProgram() function

The createProgram() function creates shader objects for the vertex shader and fragment shader (lines 31 and 32) by calling the loadShader() function. The shader object returned by the loadShader() function has been specified with source code and has been successfully compiled.

The createProgram() function itself is responsible for creating the program object (line 38), and then assigning the previously created vertex shader and fragment shader to the program object (lines 44 and 45).

Next, the function connects to the program object (line 48) and checks whether the connection is successful (line 51). If the connection is successful, the program object is returned (line 60).

Finally take a look at the loadShader() function as shown below. This function is called by the createProgram() function.

loadShader() function

The loadShader() function first creates a shader object (line 72), then specifies the source code for the shader object (line 79), compiles it (line 82), and then checks whether the compilation was successful (line 85 ), if compiled successfully without errors, the shader object is returned.