-
Notifications
You must be signed in to change notification settings - Fork 0
6. Textures and Image Loading
- 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

-
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
- 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.

- 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)

- 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
- 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

- 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
-
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);
- 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
- 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
- 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.