Textures - jgoffeney/Cesium4Unreal GitHub Wiki

Back

General

Creating and Using Textures

Resources in OpenGL are created by generating an object and then bound to make them the currently active resource of a type.

glGenTextures(GLsizei n, GLuint * textureIds)

Generates new texture objects

  • Parameters
    • n: the number of texture object to generate
    • textureIds: returns the ids for each generated texture object

glBindTexture(GLenum target, GLuint textureId)

Makes the texture active for applying operations and specifies the kind of texture it is. The texture type is permanent and can not be changed later (or an error will occur).

  • Parameters
    • target: the type of texture to set it to (ex. GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, ...)
    • textureId: the id of the texture object to bind
// Allocates a texture resource object and returns an id (pass an array for multiple textures)
GLuint texId;
glGenTextures(1, &texId);

// Bind the texture to apply operations to it 
glBindTexture(GL_TEXTURE_2D, texId);

Coordinates within a texture range in values from 0.0 to 1.0 where the origin is the bottom-left corner. The two dimensional coordinate pair are referred to as UV coordinates. This allows something like a shader or texture mapping to not have to be aware of the dimensions or resolution of a source image to use it.

Texture Parameters

The function glTexParameter (or glTextureParameter) is used to set properties of the texture. There are vector forms of the function to set multiple values.

glTexParameter{f i}(GLenum target, GLenum paramName, {GLfloat GLint} paramValue)

  • Parameters
    • target: the current texture's target type
    • paramName: the enum for the texture parameter
    • paramValue: the value for the texture parameter

Wrapping

Wrapping indicates how a texture will be treated at and past its edges as UV coordinates can be outside of the range of 0.0 and 1.0. For example it is common to use values greater than 1.0 to tile a texture on an surface.

The parameters indicate which dimensions wrapping to use. Note that it uses S and T indicate dimensions rather than U and V because the former is the notation for the normalized surface coordinates (the thing having a texture applied to it) and the latter are the normalized coordinates for the texture image.

  • paramName
    • GL_TEXTURE_WRAP_S: set the value for texture wrapping in the surface S dimension
    • GL_TEXTURE_WRAP_T: set the value for texture wrapping in the surface T dimension
    • GL_TEXTURE_BORDER_COLOR: set a color vector as a constant value to set when reading past the edge
  • paramValue
    • GL_REPEAT: when reading past the edge wrap around (tiles the texture)
    • GL_MIRRORED_WRAP: when reading past the edge mirror the texture (tiles the texture as mirror images)
    • GL_CLAMP_TO_EDGE: when reading past the edge just repeat the nearest edge value
    • GL_CLAMP_TO_BORDER: when reading past the edge set it to a constant color (use another glTexParameterfv with GL_TEXTURE_BORDER_COLOR to set the color).
// For the currently bound texture set texture wrapping to tile the image
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

Filtering

When sampling (reading) a pixel value from a texture the UV coordinates may not map to a pixel center so the type of interpolation has to be set. It also indicates how to express the texture when the surface it is bound to is scaled up or down.

  • paramName

    • GL_TEXTURE_MIN_FILTER: set the filtering type for scaling the texture down
    • GL_TEXTURE_MAX_FILTER: set the filtering type for scaling the texture up
  • paramValue

    • GL_NEAREST: read the closest nearest pixel value
    • GL_LINEAR: perform linear interpolation of the nearest neighbors
// For the currently bound texture set reading as bilinear interpolation
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Loading Texture Images

At this point the texture does not contain any data or have any indication of what kind of data should be associated with it. The function glTexImage2D handles this and allows for loading image data to it.

glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * data)

  • Parameters
    • target: the current texture's target type
    • level: the level of detail index for the mipmapping where 0 is the base image level (and the value to use when mipmapping is not being used)
    • internalFormat: the number of color components / channels and data type for the texture as specified by an enum value.
    • width: the texture width in pixels
    • height: the texture height in pixels
    • border: has to be 0
    • format: specifies the format (num channels) of the supplied pixel data as an enum
    • type: the data type of the pixel data
    • data: the source pixel data array

Typical example for loading image data

// Loads a buffer of RGBA 8-bit data to the texture 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());

Example for creating a texture to be used as a render target for a single channel of 32-bit floating point data.

// Create the source array of the texture size and set to 0.0
std::vector<GLfloat> buffer(width * height, 0.0);

// Load the currently bound texture with 32 bit floating point values
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, buffer.data())

Texture Units

A video card can handle a maximum number of texture references simultaneously. This is not a limit for the number of textures but instead the number the GPU can use at once. Each texture is mapped to a texture unit starting at GL_TEXTURE0 which is the default when using glBindTexture. By using glActiveTexture followed by glBindTexture the texture object will be associated with the texture unit. The texture unit value should be between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

glActiveTexture(GLenum texture)

  • Parameters
    • texture: the texture unit number enum. OpenGL has enums like GL_TEXTURE1 but maxes out at GL_TEXTURE31 while GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS for OpenGL3.x equals 48. So instead you can use GL_TEXTURE0 + 33 to access higher number texture units.

Note GL_TEXTURE0 does not equal 0 so don't do something like glActiveTexture(2) but instead glActiveTexture(GL_TEXTURE2). This also comes into play when setting the texture as a shader input.

// Binds the texture object of texId to texture unit 3
glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_2D, texId);

Setting Textures as Shader Inputs

Before a trying to find the location of shader variables the shader programs need to be set up via glCreateProgram and set to active via glUseProgram.

To set a texture as an input the function glUniform1i is used with the parameters of the shader's uniform variable location and the number of the texture unit it is bound to. NOTE: for the texture unit GL_TEXTURE3 then the number 3 is passed to the function and not the enum GL_TEXTURE3.

This example demonstrates setting two textures as inputs to a shader that has the variables sourceTexture0 and sourceTexture1 of type uniform sampler2D.

// Enable the shader program of interest
glUseProgram(progId);

// Get the uniform variable locations for the texture samplers 
GLint sourceTexLoc0 = glGetUniformLocation(progId, "sourceTexture0");
GLint sourceTexLoc1 = glGetUniformLocation(progId, "sourceTexture1");

// Specify the texture units values for clarity
int texUnit0 = 0;
int texUnit1 = 1;

// Set the active texture unit to 0
glActiveTexture(GL_TEXTURE0 + texUnit0);

// Bind the first texture (previously generated) to the texture unit 
glBindTexture(GL_TEXTURE_2D, texId0);

// Set the shader's variable "sourceTexture0" to texture unit 0
glUniform1i(sourceTexLoc0, texUnit0);

// Repeat for texture unit 1 and the next texture
glActiveTexture(GL_TEXTURE0 + texUnit1);
glBindTexture(GL_TEXTURE_2D, texId1);
glUniform1i(sourceTexLoc1, texUnit1);

//Repeat for as many textures as you need.
...

Shader Texture Functions

Reading a Texture

The texture function reads a texture sampler value(s) at a given texture coordinate. There are several overrides of the function for different inputs.

vec4 texture(sampler2D tex, vec2 texcoord) vec4 texture(usampler2D tex, vec2 texcoord)

  • Parameters
    • tex: the texture sampler object
    • texcoord: the normalized texture coordinates for the location to read from
  • Returns
    • A four element vector of the texture values by channels (even if the texture has fewer than 4 channels).
uniform sampler2D sumTexture;   // The sum of the computed height values for the pixel
uniform usampler2D countTexture; // The count of the overlapping values for the pixel

void main(void){
  \\ Read a single float
  float pixelSum = texture(sumTexture, texcoord).r;

  \\ Read a single unsigned int
  uint pixelCount = texture(countTexture, texcoord).r;
}

Getting Texture Size

The function textureSize gets the dimensions of the texture in pixels.

vec2 textureSize(sampler2D tex, int lod)

  • Parameters
    • tex: the texture sampler object
    • lod: the level of detail
  • Returns
    • the texture dimensions in pixels
uniform sampler2D sumTexture;   // The sum of the computed height values for the pixel

void main(void){
  vec2 tex_offset = 1.0 / textureSize(sumTexture, 0); // gets size of single texel
}
⚠️ **GitHub.com Fallback** ⚠️