Skip to content

6. Textures and Image Loading

Shane edited this page Dec 27, 2023 · 1 revision

Textures

  • Textures are images used to add extra detail to an object
  • Textures can also be used to hold generic data... but thats a more advanced topic
  • Usually 2D but can also have 1D and 3D Textures
  • Points on textures are "texels" not pixels
  • Texels are defined between 0 and 1
  • So to sample a point at the top-middle you reference texel (0.5, 1)
  • Map texels to vertices
  • Interpolation over each fragment will calculate appropriate texels in between the assigned texels

Screenshot 2023-12-27 at 8 14 27 am

Texture Objects

  • Creating textures works much like create VBOs/VAOs

  • glGenTextures(1, &texture);

  • glBindTexture(GL_TEXTURE_2D, texture);

  • There are different types of texture, such as GL_TEXTURE_1D, GL_TEXTURE_3D and GL_TEXTURE_CUBE_MAP

  • glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

  • First argument: Texture Target (what we have bound our texture to)
  • Second Argument: Mipmap Level
  • Third Argument: Format of the stored data. RGB: Red,Green, Blue. Also RGBA which has an Alpha Channel (transparency). as well as Several others
  • Fourth and Fifth Argument: Width and Height of the texture
  • Sixth Argument: This should always be 0. Legacy concept handling texture borders that OpenGL doesn't utilise anymore
  • Seventh Argument: Format of the data being loaded (as opposed to stored on the third argument)
  • Eighth Argument: The data type of the values (int,float,byes,etc).
  • Ninth Argument: The data itself

MipMaps

  • Resolution limitations for textures
  • The closer we get to an object, the more pixelated the texture becomes. Further away, it attempts to render multiple texels on one pixel
  • Solution: Create multiple versions of image at different resolutions and switch between them based on distance.

Screenshot 2023-12-27 at 8 26 37 am

Texture Parameters - Filters

  • What if we try to render off center of texels?
  • Two possibilities:
  • Nearest: Use the texel with most overlap (creates a pixelated effect)
  • Linear: Use a weighted average of surrounding texels (blends pixel boundaries)
  • Linear more common in most applications

  • Nearest used if you want a pixelated effect (such as a retro game)

  • glTexParameter: used to set texture rendering parameters

  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

  • GL_TEXTURE_MIN_FILTER: Filter to apply when texture is made smaller (is further away)
  • GL_TEXTURE_MAG_FILTER: Filter to apply when texture is made bigger (is closer)
  • GL_LINEAR: Linear filter (blends surrounding texels)
  • GL_NEAREST: Nearest filter (picks nearest texel to sampling point)

Screenshot 2023-12-27 at 8 40 35 am

  • Left Image: Using Nearest has a more pixelated look, good for certain visual styles
  • Right Image: Using Linear, blends texels together to create a smoother look. Works well on complex textures, less so on simple ones

Texture Parameters - Wrap

  • What if we try to sample a point outside the 0,1 range?
  • Multiple ways to handle it:
  • Repeat the texture.
  • Repeat a mirrored form of the texture
  • Extend pixels at the edge
  • Apply a coloured border
  • Can use glTexParameter to define how this is handled

  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

  • glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

  • GL_TEXTURE_WRAP_S: How to handle wrapping on "s-axis" (x-axis)
  • GL_TEXTURE_WRAP_T: How to handle wrapping on "t-axis" (t-axis)
  • GL_REPEAT: Repeat texture
  • GL_MIRRORED_REPEAT: Repeat and mirror texture
  • GL_CLAMP_TO_EDGE: Extend pixels at edge
  • GL_CLAMP_TO_BORDER: Apply coloured border

Screenshot 2023-12-27 at 8 51 49 am

Loading Images for Textures

  • Could write own image loader...
  • But will get confusing for handling each image type (bmp, jpg, png, gif, tga, etc...)
  • Image Loader libraries do the work for us
  • Popular library: Simple OpenGL Image Library (SOIL)
  • For the sake of simplicity, we'll use a smaller library...
  • stb_image

Using stb_image

  • Only requires the header file, so lightweight

  • Must start project with: #define STB_IMAGE_IMPLEMENTAION

  • unsigned char *data = stbi_load("image.jpg", &width, &height, &bitDepth, 0);

  • Might need to flip image

  • stbi_set_flip_vertically_on_load(true);

Texture Samplers

  • Textures in Shaders are accessed via "Samplers"
  • Textures are attached to a "Texture Unit"
  • Samplers access textures attached to their texture Unit
  • In shader, use "sampler2D" type
  • To get the value of a texel, use GLSL "texture" function
  • texture(textureSampler, TexCoord);
  • texCoord: the interpolated texel co-ordinate in the Fragment Shader

Texture Units

  • Bind texture to desired Texture Unit:
  • glActiveTexture(GL_TEXTURE0);
  • glBindTexture(GL_TEXTURE_2D, textureID);
  • Esnure sampler2D variables know which Texture Unit to access:
  • glUniform1i(uniformTextureSampler, 0);
  • Value attached to uniform is the Texture unit number

Summary

  • Texture use texels between 0 and 1
  • Texels are bound to vertices and values are interpolated
  • Mipmaps handle level-of-detail more efficiently
  • Texture Filtering changes how teels are blended (or aren't blended) based on size on screen
  • Texture Wrapping changes how textures are handled for texel values outside of the 0, 1 range
  • Wrapping and Filtering are defined using the glTexParameteri function
  • Load images with thrid-party libraries for convenienve
  • SOIL is a popular library for this but stb_image is more lightweight and good for this project
  • Textures attach to Texture Units, samplers read from Textures attached to Texture Units.

Clone this wiki locally