Portal:

  1. Overview of WebGL – Principles
  2. Drawing points and triangles

preface

To pick up where we left off, in the last section we explained how to draw points and triangles using WebGL. We passed vertex data to WebGL using WebGLBuffer. We leave two questions:

  1. gl.vertexAttribPointerThe parameters of thestrideandoffsetWhat exactly do these two parameters do?
  2. There are more than one in a programWebGLBufferHow to deal with it?

Today we’re going to solve both of those questions in real life.

Real – Draw color gradient triangle

Before we drew a solid color triangle, now we draw a gradient triangle, we set the color of the three vertices to red, green, and blue. We expect the following results:

To prepare data

We change the previous vertex data to:

const pointPos = [
    -0.5.0.0.1.0.0.0.0.0.1.0.0.5.0.0.0.0.1.0.0.0.1.0.0.0.0.5.0.0.0.0.1.0.1.0,];Copy the code

The first two digits of each row indicate the position of the vertex, and the following four digits make up the RGBA value, which is the color of the vertex. Since we are mixing vertex position and color information here, we also need to tell WebGL how to read our data. The gl.vertexattribPointer API we used earlier tells WebGL how to read data. We need to modify the following code

const a_position = gl.getAttribLocation(program, "a_position");
const a_color = gl.getAttribLocation(program, "a_color");
gl.vertexAttribPointer(
    a_position,
    2,
    gl.FLOAT,
    false.Float32Array.BYTES_PER_ELEMENT * 6.0
);

gl.vertexAttribPointer(
    a_color,
    4,
    gl.FLOAT,
    false.Float32Array.BYTES_PER_ELEMENT * 6.Float32Array.BYTES_PER_ELEMENT * 2
);
gl.enableVertexAttribArray(a_position);
gl.enableVertexAttribArray(a_color);
Copy the code

We noticed that we changed the last two arguments to gl.vertexAttribPointer. Recall the function signature of this API:

Parameter names meaning
index Specifies the vertex property to modify
size The number of components per vertex attribute, in other words, the number of pieces of data that make up a vertex attribute
type Type of data
normalized Whether to normalize
stride The offset between vertices
offset The offset of a portion of the bytes in the vertex property array
  • Stride: The offset between the vertices, colloquially speaking, is only the size that each vertex occupies. One vertex uses six Float32 values, so each vertex occupies the following space: float32Array. BYTES_PER_ELEMENT * 6.

  • Offset: The offset of a portion of bytes in the vertex attributes array. Here we use the code above as an example. The position of the vertex occupies two digits and the size of the position is float32Array. BYTES_PER_ELEMENT * 2. The position occurs at the first of each line, so the offset is 0. The color information of the vertices takes up four digits. Each row is preceded by the position of the vertices that occupy float32Array. BYTES_PER_ELEMENT * 2, so offset is float32Array. BYTES_PER_ELEMENT * 2

Modify the Shader

Now that the data is ready, we need to modify the code in the shader:

const vertexShader = ` attribute vec4 a_position; // Add an attribute variable of a_color, attribute vec4 a_color; // Add a new variable varying v_color varying VEC4 V_color; void main () { gl_Position = a_position; v_color = a_color; } `;

const fragmentShader = ` precision mediump float; varying vec4 v_color; void main () { gl_FragColor = v_color; } `;
Copy the code

The two variables that need to be explained here are A_color and v_color.

A_color should make a lot of sense because, like a_position, it accepts incoming data from outside. So what does v_color do? Note the storage qualifier VARYING in front of v_color, which represents the amount of a change.

Let’s recall the process of rendering pipeline: from vertex shader to pixel shader, we need to go through a rasterization process. This step is actually to interpolate each pixel in the assembled pixel according to the existing vertex information, so as to get the basic information of each pixel.

V_color = a_color is telling WebGL that I need the a_color variable to interpolate. A variable of the same name must be defined in the fragment shader so that the interpolated value can be used directly in the fragment shader.

At this point, our code has been modified. You should be able to get the correct results.

How to separate color and location information

If you are confused by the way you pass data to vertices, you can also pass vertex position information and color information separately.

To prepare data

This time, we separate the position and color information into two arrays.

const pointPos = [-0.5.0.0.0.5.0.0.0.0.0.5];
const pointColor = [1.0.0.0.0.0.1.0.0.0.1.0.0.0.1.0.0.0.0.0.1.0.1.0];
Copy the code

We also need two Webglbuffers to hold two sets of data

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointPos), gl.STATIC_DRAW);

const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointColor), gl.STATIC_DRAW);
Copy the code

Here, you need to be especially careful when passing data to WebGL. Always bindBuffer before calling vertexAttribPointerAPI, which means that only the current WebGLBuffer is read in this way.


gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(
    a_position,
    2,
    gl.FLOAT,
    false.Float32Array.BYTES_PER_ELEMENT * 2.0
);
// This binds the a_position in the shader to buffer
gl.enableVertexAttribArray(a_position);
Copy the code

For color data, similarly:


gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.vertexAttribPointer(
    a_color,
    4,
    gl.FLOAT,
    false.Float32Array.BYTES_PER_ELEMENT * 4.0
);
// Bind a_color in shader to colorBuffer
gl.enableVertexAttribArray(a_color);
Copy the code

At this point, we have completed the separation of position information and color information. I’m sure you’ll get the same result as above.

conclusion

Ok, today I added a lot of color to the triangle. We talked about how to pass information other than vertex position. We can mix other information and position information together by using a WebGLBuffer, but we need to manually calculate the size of each vertex and the offset of each set of information within each vertex. But this efficiency is relatively high. If you feel cumbersome, you can also use multiple Webglbuffers for information transmission, the disadvantage is not as efficient as the above information transmission.

If you think the article is good, remember to like 👍 oh ~

See the full code here