DEV Community

loading...
Cover image for WebGL Month. Day 25. Mipmaps

WebGL Month. Day 25. Mipmaps

lesnitsky profile image Andrei Lesnitsky ・3 min read

This is a series of blog posts related to WebGL. New post will be available every day

GitHub stars
Twitter Follow

Join mailing list to get new posts right to your inbox

Source code available here

Built with

Git Tutor Logo


Hey 👋

Welcome to WebGL month

Today we're going to learn one more webgl concept which might improve the quality of the final rendered image

First we need to discuss how color is being read from texture.

Let say we have a 1024x1024 image, but render only a 512x512 area on canvas. So each pixel in resulting image represents 4 pixels in original texture.

Here's where gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter) plays some role

There are several algorithms on how to read a color from the texture

  • gl.LINEAR - this one will read 4 pixels of original image and blend colors of 4 pixels to calculate final pixel color

  • gl.NEARETS will just take the closest coordinate of the pixel from original image and use this color. While being more performant, this method has a lower quality

Both methods has it's caveats, especially when the size of area which need to be painted with texture is much smaller than original texture

There is a special technique which allows to improve the quality and performance of rendering when dealing with textures. This special textures are called [mipmaps] – pre-calculated sequences of images, where each next image has a progressively smaller resolution. So when fragment shader reads a color from a texture, it takes the closest texture in size, and reads a color from it.

In WebGL 1.0 mipmaps can only be generated for textures of "power-of-2" size (256x256, 512x512, 1024x1024 etc.)

And that's how mipmap will look like for our dirt cube

Mipmap

Don't worry, you don't need to generate such a sequence for all your textures, this could be done automatically if your texture is a size of power of 2

📄 src/minecraft-terrain.js


  const State = {};

+ /**
+  *
+  * @param {WebGLRenderingContext} gl
+  */
  export async function prepare(gl) {
      const vShader = gl.createShader(gl.VERTEX_SHADER);
      const fShader = gl.createShader(gl.FRAGMENT_SHADER);
      await loadImage(textureSource).then((image) => {
          const texture = createTexture(gl);
          setImage(gl, texture, image);
+ 
+         gl.generateMipmap(gl.TEXTURE_2D);
      });

      setupAttributes(gl);

And in order to make GPU read a pixel color from mipmap, we need to specify TEXTURE_MIN_FILTER.

📄 src/minecraft-terrain.js

          setImage(gl, texture, image);

          gl.generateMipmap(gl.TEXTURE_2D);
+         gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
      });

      setupAttributes(gl);

NEAREST_MIPMAP_LINEAR will choose the closest size mipmap and interpolate 4 pixels to get resulting color

That's it for today!

Thanks for reading, see you tomorrow 👋


GitHub stars
Twitter Follow

Join mailing list to get new posts right to your inbox

Source code available here

Built with

Git Tutor Logo

Discussion (0)

pic
Editor guide