Portal:

  1. Overview of WebGL – Principles
  2. Drawing points and triangles
  3. Drawing points and Triangles (Advanced)

preface

In the last video, we added a little bit of fun to the triangle we drew, and we drew a triangle with a gradient. This is essentially giving the vertex of the triangle color information except the position information. In this section we continue to add some additional information to the vertices of the triangle. In this section we will add texture coordinates to the triangle.

Actual practice – Drawing pictures (textures)

To prepare data

We drew triangles earlier, but to better illustrate this example, we will now change the triangles we drew to rectangles. We can make a rectangle out of two triangles.

We modify our data as follows:

// Change the vertex position data to:
const pointPos = [
    -1.1,
    -1, -1.1, -1.1, -1.1.1,
    -1.1,];// Add texture coordinates to vertices
const texCoordPos = [
    0.1.0.0.1.0.1.0.1.1.0.1
];
Copy the code

Texture coordinates are the coordinates on the texture image, through which the texture color can be obtained from the texture image. Texture coordinates in WebGL system are two-dimensional. As shown above. In the figure above, texture coordinates are lower left (0,0), lower right (1,0), upper right (1,1), and upper left (0,1). Texture coordinates are very generic because the coordinate value is independent of the size of the image itself, and the coordinate value in the upper right corner of both 128×128 and 128×256 images is always (1,1).

The essence of drawing an image using WebGL is actually “pasting” the image onto our drawing geometry. How do I paste? Using the texture coordinates that we give the vertices.

Remember our previous in WebGL overview – rasterization process of principle mentioned in the article, through the rasterizer, our every piece of RMB will get a texture coordinate, according to the coordinates to query on the texture image, take a look at this coordinates texels in the corresponding color value is how much, and then assign the value to the current fragment.

The data transfer

Now there is the problem of how to pass texture images to the GPU. As mentioned in WebGL Overview – Principles, similar to passing vertex data, we use the WebGLBuffer object to pass vertex data, so we can use the WebGLTexture object to pass textures to and from WebGL.

    // Create a texture
    let texture = gl.createTexture();
    // Bind the texture
    gl.bindTexture(gl.TEXTURE_2D, texture);
    // Pass texture data
    image.onload = function () {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.drawArrays(gl.TRIANGLES, 0.6);
}
Copy the code

So that’s how the data is passed. Now let’s modify the Shader program


const vertexShader = ` attribute vec4 a_position; // Change the color information to texture coordinate information attribute vec2 a_texCoord; varying vec2 v_texCoord; void main () { gl_Position = a_position; v_texCoord = a_texCoord; } `;

const fragmentShader = ` precision mediump float; varying vec2 v_texCoord; // Declare a uniform variable to save the uniform sampler2D u_texture; Void main () {// Use the built-in texture2D function to sample the texture gl_FragColor = texture2D(u_texture, v_texCoord); } `;
Copy the code

At this point, let’s try to run our program. A ~ Oh ~, you might get A black screen. We opened the console and found an error like this:


[.WebGL-0x7fb3a482c400]RENDER WARNING: texture bound to texture unit 0 is not renderable. It might be non-power-of-2 or have incompatible texture filtering (maybe)?
Copy the code

This error message tells us that the image could not be rendered because the size is not an integer power of 2 or because of incompatible sampling patterns.

Let’s try to change the picture to a power of two. As if still no, still the same mistake.

After checking the data, we need to set some parameters of the WebGLTexture object. For example, if the image is smaller than the drawing area, the image will be treated. Some points will need to be interpolated. It’s up to us to tell WebGL.

// This tells WebGL to use linear interpolation for sampling if the texture needs to be reduced
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// This tells WebGL to use linear interpolation if textures need to be sampled
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// Tell WebGL to take the boundary value if the texture coordinates exceed the maximum/minimum value of the S-coordinate
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// Tell WebGL to take boundary values if texture coordinates exceed the maximum/minimum t coordinates
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
Copy the code

We use texParameteri to tell WebGL how we should interpolate. There are some other values that you can explore for yourself.

I tested it again and found it worked. We’ve got a picture.

But wait! Why is the picture upside down? This is due to the fact that the t-axis (or Y-axis) orientation of WebGL texture coordinates is the opposite of the Y-axis orientation of PNG, BMP, JPG, etc. Therefore, you need to invert the Y-axis of the image to map the image properly (or you can manually invert the T-coordinate in the shader).

We can call the API provided by WebGL

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
Copy the code

So we have a normal picture.

conclusion

OK, that’s the end of today’s texture drawing tutorial. Now that you’ve learned how to draw an image in WebGL, which is completely different from how Canvas2D draws images, hopefully you’ll get a feel for the process. Let’s go through the basic process of drawing an image again:

  1. Adds texture coordinate information to vertices
  2. createWebGLTextureObject used to pass texture information. Note that we also need an additional way to set up the texture sampling.
  3. Modify shader to use built-in shadertexture2DMethod sampling

Wait, don’t go. Now I want to show you the original picture of Gundam. Gundam looks very handsome, doesn’t he?

After looking at the original image, do you think the image we drew earlier looks a little strange? It looks like… The deformation? So, why? How do you solve this? Or what if I want the picture to zoom in, zoom out, rotate? We’ll find out in the next video.

Don’t forget to like it!

See the full code here