primers
Following the WebGL basics, do a simple example of drawing a line.
Mainly refer to the following two articles:
-
Draw a triangle
-
Origin
-
My GitHub
Draw a line
I won’t explain each function in detail below, but I prefer to get a feel for the overall logic first and then look it up as needed.
Create a WebGL context
The basic concept is to use WebGL with the Canvas element:
<canvas id="demo" width="300" height="200"></canvas>
Copy the code
const canvasObj = document.querySelector("#demo");
const glContext = canvasObj.getContext("webgl");
if(! glContext) { alert("Browsers do not support WebGL");
return;
}
Copy the code
Then prepare the vertex data.
Prepare and buffer vertex data
In WebGL all objects are in 3D space and drawing a line requires two vertices, each with a 3D coordinate:
let vertices = [
-0.5, -0.5.0.0.0.5, -0.5.0.0
];
Copy the code
There are several types of buffers. The vertex buffer object is of type gl.array_buffer.
/** * set buffer *@param {*} Gl WebGL context *@param {*} VertexData specifies the vertexData */
function setBuffers(gl, vertexData) {
// Create a blank buffer object
const buffer = gl.createBuffer();
// Bind the target
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// WebGL does not support using JavaScript primitive array types directly
const dataFormat = new Float32Array(vertexData);
// Initialize the data store
gl.bufferData(gl.ARRAY_BUFFER, dataFormat, gl.STATIC_DRAW);
},
Copy the code
The bufferData method copies the data to the current binding buffer object and provides parameters to manage the given data:
-
STATIC_DRAW: The contents of the buffer are likely to be used frequently and will not change often.
-
DYNAMIC_DRAW: The contents of the buffer may be used frequently and change frequently.
-
STREAM_DRAW: The contents of the buffer may not be used very often.
The data for the line doesn’t change, it stays the same every render, so the type used here is STATIC_DRAW. Now that you have the vertex data stored in memory on your video card, start preparing the vertex shaders.
Vertex shader
Vertex shaders need to be written in GLSL ES, and there are two types of front-end writing:
-
Script tag wrapped, used like a DOM object.
-
A pure string.
<script id="shader" type="x-shader/x-vertex">
attribute vec3 vertexPos;
void main(void){
gl_Position = vec4(vertexPos, 1);
}
</script>
<script>
const shader = document.getElementById('shader').innerHTML,
</script>
Copy the code
Each vertex has a 3D coordinate, creating an input variable vertexPos of type VEC3, which represents a vector of triples floating point numbers.
Gl_Position is a variable built into the shader. In GLSL, a variable has up to four components, the last of which is used for perspective division. The value set by gl_Position becomes the output of the vertex shader. Recall here the state machine mentioned in the basic concept.
Here is the pure character form:
/** * Create vertex shader *@param {*} Gl WebGL context */
function createVertexShader(gl) {
// Vertex shader GLSL code
const source = ` attribute vec3 vertexPos; void main(void){ gl_Position = vec4(vertexPos, 1); } `;
// Create a shader
const shader = gl.createShader(gl.VERTEX_SHADER);
// Sets the vertex shader code
gl.shaderSource(shader, source);
/ / compile
gl.compileShader(shader);
// Check whether the compilation succeeded
if(! gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert("Compiling shader error:" + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
Copy the code
In order for WebGL to use the shader, its source code must be compiled dynamically at run time.
-
The createShader function creates a shader object of type gl.vertex_shader.
-
The function compileShader compiles.
Next, prepare the fragment shader.
Fragment shader
The fragment shader is also written in GLSL ES. What the fragment shader does is calculate the color output at the end of the pixel, which simply specifies the output white. Gl_FragColor is A built-in variable that represents A color and has four components that correspond to R, G, B, and A.
/** * Create fragment shader *@param {*} Gl WebGL context */
function createFragmentShader(gl) {
// Fragment shader GLSL code
const source = 'void main(void){gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); } `;
// Create a shader
const shader = gl.createShader(gl.FRAGMENT_SHADER);
// Sets the fragment shader code
gl.shaderSource(shader, source);
/ / compile
gl.compileShader(shader);
// Check whether the compilation succeeded
if(! gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert("Compiling shader error:" + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
},
Copy the code
Once both shaders are ready, they need to be linked together before they can be used.
Shader program
A shader program object is a version of a shader that has been merged and eventually linked. When linking shaders to a program, it links the output of each shader to the input of the next shader. When the output and input do not match, you get a connection error.
-
The createProgram function creates the object;
-
AttachShader add shader;
-
LinkProgram link to add shader.
When the shader needs to be activated, the useProgram function is called with the object as an argument.
/** * Initialize shader program *@param {*} Gl WebGL context *@param {*} VertexShader vertexShader@param {*} FragmentShader fragmentShader */
function initShaderProgram(gl, vertexShader, fragmentShader) {
// Create a shader object
const shaderProgram = gl.createProgram();
// Add shaders
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
// Multiple shaders merge links
gl.linkProgram(shaderProgram);
// Check whether the creation is successful
if(! gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Cannot initialize shader program:" + gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
Copy the code
So far, you’ve sent input vertex data to the GPU and instructed the GPU how to process it in vertex and fragment shaders. All that’s left is to draw.
draw
-
The vertexAttribPointer function tells WebGL how to interpret vertex data;
-
The enableVertexAttribArray function enables the vertex property, which is disabled by default.
-
The useProgram function activates the shader.
-
The drawArrays function draws. The first argument is the type of pixel to draw. It draws a line, so gl.line_strip.
/** * Initialize shader program *@param {*} Gl WebGL context *@param {*} ShaderProgram shaderProgram object */
function draw(gl, shaderProgram) {
// Get the corresponding data index
const vertexPos = gl.getAttribLocation(shaderProgram, "vertexPos");
// Parse vertex data
gl.vertexAttribPointer(vertexPos, 3, gl.FLOAT, false.0.0);
// Enable vertex attributes. Vertex attributes are disabled by default.
gl.enableVertexAttribArray(vertexPos);
// Activate the shader
gl.useProgram(shaderProgram);
/ / to draw
gl.drawArrays(gl.LINE_STRIP, 0.2);
}
Copy the code
The sample
Here’s an example, and the overall logic looks something like this:
const canvasObj = document.querySelector("#demo");
const glContext = canvasObj.getContext("webgl");
let vertices = [-0.5, -0.5.0.0.0.5, -0.5.0.0]; // Vertex data
setBuffers(glContext, vertices); // Buffer data
const vertexShader = createVertexShader(glContext); // Vertex shader
const fragmentShader = createFragmentShader(glContext); // Fragment shader
const shaderProgram = initShaderProgram(
glContext,
vertexShader,
fragmentShader
); // The shader program object
draw(glContext, shaderProgram); / / to draw
Copy the code
There are a lot of methods and variables involved in this, and it’s really confusing at first, but you’ll get used to it after you read it a few times and type the code yourself.
Some of the questions raised during this period are summarized in the JavaScript WebGL Basic Questions section.
The resources
-
Hello, triangle
-
WebGL lessons
-
WebGL MDN
When I first saw the King rank, I thought it was an inspirational movie.
But a recent episode shattered that notion. The ending song is great!