Texture: Difference between revisions

From OpenGL Wiki
Jump to navigation Jump to search
Programs and textures: Added link to new page.
No more quirks
 
(72 intermediate revisions by 14 users not shown)
Line 1: Line 1:
A '''texture''' is an [[OpenGL Objects|OpenGL Object]] that contains one or more images that all have the same [[Image Formats|image format]]. A texture can be used in two ways. It can be the source of a texture access from a [[Shader]], or it can be used as a render target.
{{object float}}
 
A '''texture''' is an [[OpenGL Objects|OpenGL Object]] that contains one or more images that all have the same [[Image Formats|image format]]. A texture can be used in two ways: it can be the source of a texture access from a [[Shader]], or it can be used as a render target.


== Theory ==
== Theory ==


For the purpose of this discussion, an ''image'' is defined as a single array of pixels of a certain dimensionality (1D, 2D, or 3D), with a particular size, and in a specific [[Image Formats|format]].
For the purpose of this discussion, an ''image'' is defined as a single array of pixels of a certain dimensionality (1D, 2D, or 3D), with a particular size, and a specific [[Image Formats|format]].


A texture is a container of one or more images. But textures do not store arbitrary images; a texture has specific constraints on the images it can contain. There are three defining characteristics of a texture, each of the defining part of those constraints: the texture type, texture size, and the image format used for images in the texture. The texture type defines the arrangement of images within the texture. The size defines the size of the images in the texture. And the image format defines the format that all of these images share.
A texture is a container of one or more images. But textures do not store arbitrary images; a texture has specific constraints on the images it can contain. There are three defining characteristics of a texture, each of them defining part of those constraints: the texture type, texture size, and the image format used for images in the texture. The texture type defines the arrangement of images within the texture. The size defines the size of the images in the texture. And the image format defines the format that all of these images share.


There are a number of different types of textures. These are:
There are a number of different types of textures. These are:


* GL_TEXTURE_1D: Images in this texture all are 1-dimensional. They have width, but no height or depth.
* {{enum|GL_TEXTURE_1D}}: Images in this texture all are 1-dimensional. They have width, but no height or depth.
* GL_TEXTURE_2D: Images in this texture all are 2-dimensional. They have width and height, but no depth.
* {{enum|GL_TEXTURE_2D}}: Images in this texture all are 2-dimensional. They have width and height, but no depth.
* GL_TEXTURE_3D: Images in this texture all are 3-dimensional. They have width, height, and depth.
* {{enum|GL_TEXTURE_3D}}: Images in this texture all are 3-dimensional. They have width, height, and depth.
* [[Rectangle Textures|GL_TEXTURE_RECTANGLE]]: The image in this texture (only one image. No mipmapping) is 2-dimensional. Texture coordinates used for these textures are not normalized.
* {{enum|[[Rectangle Texture|GL_TEXTURE_RECTANGLE]]}}: The image in this texture (only one image. No mipmapping) is 2-dimensional. Texture coordinates used for these textures are not normalized.
* [[Texture Buffers|GL_TEXTURE_BUFFER]]: The image in this texture (only one image. No mipmapping) is 1-dimensional. The storage for this data comes from a [[Buffer Objects|Buffer Object]].
* {{enum|[[Texture Buffer|GL_TEXTURE_BUFFER]]}}: The image in this texture (only one image. No mipmapping) is 1-dimensional. The storage for this data comes from a [[Buffer Objects|Buffer Object]].
* [[Cubemap Textures|GL_TEXTURE_CUBE_MAP]]: There are exactly 6 distinct sets of 2D images, all of the same size. They act as 6 faces of a cube.
* {{enum|[[Cubemap Texture|GL_TEXTURE_CUBE_MAP]]}}: There are exactly 6 distinct sets of 2D images, each image being of the same size and must be of a square size. These images act as 6 faces of a cube.
* [[Array Textures|GL_TEXTURE_1D_ARRAY]]: Images in this texture all are 1-dimensional. However, it contains multiple sets of 1-dimensional images, all within one texture. The array length is part of the texture's size.
* {{enum|[[Array Texture|GL_TEXTURE_1D_ARRAY]]}}: Images in this texture all are 1-dimensional. However, it contains multiple sets of 1-dimensional images, all within one texture. The array length is part of the texture's size.
* GL_TEXTURE_2D_ARRAY Array: Images in this texture all are 2-dimensional. However, it contains multiple sets of 2-dimensional images, all within one texture. The array length is part of the texture's size.
* {{enum|GL_TEXTURE_2D_ARRAY}}: Images in this texture all are 2-dimensional. However, it contains multiple sets of 2-dimensional images, all within one texture. The array length is part of the texture's size.
* [[Multisample Textures|GL_TEXTURE_2D_MULTISAMPLE]]: The image in this texture (only one image. No mipmapping) is 2-dimensional. Each pixel in these images contains multiple samples instead of just one value.
* {{enum|GL_TEXTURE_CUBE_MAP_ARRAY}}: Images in this texture are all cube maps. It contains multiple sets of cube maps, all within one texture. The array length * 6 (number of cube faces) is part of the texture size.
* GL_TEXTURE_2D_MULTISAMPLE_ARRAY: Combines 2D array and 2D multisample types. No mipmapping.
* {{enum|[[Multisample Texture|GL_TEXTURE_2D_MULTISAMPLE]]}}: The image in this texture (only one image. No mipmapping) is 2-dimensional. Each pixel in these images contains multiple samples instead of just one value.
* {{enum|GL_TEXTURE_2D_MULTISAMPLE_ARRAY}}: Combines 2D array and 2D multisample types. No mipmapping.




Texture sizes have a limit based on the GL implementation. For 1D and 2D textures (and any texture types that use similar dimensionality, like cubemaps) the max size of either dimension is GL_MAX_TEXTURE_SIZE. For array textures, the maximum array length is GL_MAX_ARRAY_TEXTURE_LAYERS. For 3D textures, no dimension can be greater than GL_MAX_3D_TEXTURE_SIZE in size.
Texture sizes have a limit based on the GL implementation. For 1D and 2D textures (and any texture types that use similar dimensionality, like cubemaps) the max size of either dimension is {{enum|GL_MAX_TEXTURE_SIZE}}. For array textures, the maximum array length is {{enum|GL_MAX_ARRAY_TEXTURE_LAYERS}}. For 3D textures, no dimension can be greater than {{enum|GL_MAX_3D_TEXTURE_SIZE}} in size.


Within these limits, the size of a texture can be any value. It is advised however, that you stick to powers-of-two for texture sizes, unless you have a significant need to use arbitrary sizes.
Within these limits, the size of a texture can be any value. It is advised however, that you stick to powers-of-two for texture sizes, unless you have a significant need to use arbitrary sizes.
Line 31: Line 34:
The problem is with animation. When you slowly zoom out on a texture, you start to see aliasing artifacts appear. These are caused by sampling fewer than all of the texels; the choice of which texels are sampled changes between different frames of the animation. Even with linear filtering (see below), artifacts will appear as the camera zooms out.
The problem is with animation. When you slowly zoom out on a texture, you start to see aliasing artifacts appear. These are caused by sampling fewer than all of the texels; the choice of which texels are sampled changes between different frames of the animation. Even with linear filtering (see below), artifacts will appear as the camera zooms out.


To solve this problem, we employ mip maps. These are pre-shrunk versions of the full-sized image. Each mipmap is half the size of the previous one in the chain, using the largest dimension of the image . So a 64x16 2D texture can have 5 mip-maps: 32x8, 16x4, 8x2, 4x1, 2x1, and 1x1. OpenGL does not require that the entire mipmap chain is complete; you can specify what range of mipmaps in a texture are available.
To solve this problem, we employ mip maps. These are pre-shrunk versions of the full-sized image. Each mipmap is half the size (rounded down) of the previous one in the chain, continuing until all dimensions are 1. So a 64x16 2D texture can have 6 mip-maps: 32x8, 16x4, 8x2, 4x1, 2x1, and 1x1. OpenGL does not require that the entire mipmap chain is complete; you can specify what range of mipmaps in a texture are available.


Some texture types have multiple independent sets of mipmaps. Each face of a cubemap has its own set of mipmaps, as does each entry in an array texture. However, the texture as a whole only has one setting for which mipmaps are present. So if the texture is set up such that only the top 4 levels of mipmaps present, you must have them for ''all'' mipmap chains in the texture.
Note that the division by 2 rounds down. So a 63x63 texture has as its next lowest mipmap level 31x31. And so on.


When sampling a texture (see below), the implementation will automatically select which mipmap to use based on the viewing angle, size of texture, and various other factors.
The ''base level'' of a mipmap chain is the largest one in size. It is also the one that defines the full size of the texture. OpenGL numbers this mipmap level as 0; the next largest mipmap level is 1, and so on.


When using texture sizes that are not powers of two, the half-size of lower mipmaps is rounded down. So a 63x63 texture has as its next lowest mipmap level 31x31. And so on.
Some texture types have multiple conceptually independent sets of mipmaps. Each face of a cubemap has its own set of mipmaps, as does each entry in an array texture. However, while the chains are conceptually independent, there is only one mipmap setting per-texture. So all of the mipmap chains in a texture must have the same number of mipmaps.


The ''base level'' of a mipmap chain is the largest one. It is also the one that defines the full size of the texture. OpenGL numbers this mipmap level as 0; the next largest mipmap level is 1, and so on.
When sampling a texture (see below), the implementation will automatically select which mipmap to use based on the viewing angle, size of texture, and various other factors.


The base level of a texture does not have to be loaded. As long as you specify the range of mipmaps correctly, you can leave out any mipmap levels you want.
The base level of a texture does not have to be loaded. The valid range of mipmaps must be contiguous, but the range need not start at 0.


== Texture Objects ==
== Texture Objects ==


Textures in OpenGL are [[OpenGL Objects]], and they follow the standard conventions of such. So they have the standard <code>glGenTextures</code>, <code>glBindTexture</code>, as you would expect.
[[File:Anatomy_of_a_Texture.png|frame|alt=Anatomy of a Texture|Diagram of the contents of a texture object]]


The ''target'' parameter of <code>glBindTexture</code> corresponds to the texture's type. So when you use a freshly generated texture name, the first bind helps define the type of the texture. It is not legal to bind an object to a different target than the one it was previously bound with. So if you generate a texture and bind it as GL_TEXTURE_1D, then you should continue to bind it as such.
Textures in OpenGL are [[OpenGL Objects]], and they follow the standard conventions of such. So they have the standard {{apifunc|glGenTextures}}, {{apifunc|glBindTexture}}, as you would expect.


As with any other kind of OpenGL object, it is legal to bind multiple objects to different targets. So you can have a GL_TEXTURE_1D bound while a GL_TEXTURE_2D_ARRAY is bound.
The ''target'' parameter of {{apifunc|glBindTexture}} corresponds to the texture's type. So when you use a freshly generated texture name, the first bind helps define the type of the texture. It is not legal to bind an object to a different target than the one it was previously bound with. So if you generate a texture and bind it as {{enum|GL_TEXTURE_1D}}, then you ''must'' continue to bind it as such.


Binding a fresh object is all that is needed to give it a type. But to give it a size and format, we must call one of the <code>glTexImage*</code> functions. This will allocate storage for a particular mipmap level of the texture. To allocate all of the mipmap levels of a texture, you can call the appropriate function in a loop, from base level 0 to the the maximum mipmap level (defined by the largest dimension of the texture).
As with any other kind of OpenGL object, it is legal to bind multiple objects to different targets. So you can have a {{enum|GL_TEXTURE_1D}} bound while a {{enum|GL_TEXTURE_2D_ARRAY}} is bound.


These functions are defined as follows:
=== Texture completeness ===


  void glTexImage1D( GLenum ''target'', GLint ''level'', GLint ''internalformat'', GLsizei ''width'', GLint ''border'', GLenum ''format'', GLenum ''type'', void *''data'' );
A texture object has the concept of "completeness". A complete texture object is one which is in a logical state to be used for many operations. Until a texture is complete, it *cannot* be used in shader sampling or [[Image Load Store]] operations. And attaching an image from a texture to a [[Framebuffer Object]] requires certain forms of completeness.
  void glTexImage2D( GLenum ''target'', GLint ''level'', GLint ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLint ''border'', GLenum ''format'', GLenum ''type'', void *''data'' );
  void glTexImage3D( GLenum ''target'', GLint ''level'', GLint ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLsizei ''depth'', GLint ''border'', GLenum ''format'', GLenum ''type'', void *''data'' );
  void glTexImage2DMultisample( GLenum ''target'', GLsizei ''samples'', GLint ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLboolean ''fixedsamplelocations'' );
  void glTexImage3DMultisample( GLenum ''target'', GLsizei ''samples'', GLint ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLsizei ''depth'', GLboolean ''fixedsamplelocations'' );


The ''level'' parameter defines what mipmap level is being allocated in this function call. The ''width'', ''height'', and ''depth'' are specific to this particular mipmap level. For 1D array textures, the ''height'' means "number of entries in the array". The same goes for 2D array textures and the ''depth'' value.
A texture object is complete if it fulfills the following 3 kinds of completeness requirements.


The ''target'' value specifies what target will have this operation performed on it. Certain targets are not allowed under certain functions. <code>glTexImage3D</code> can only be used with GL_TEXTURE_3D and GL_TEXTURE_2D_ARRAY targets. <code>glTexImage2D</code> can only be used with GL_TEXTURE_2D, GL_TEXTURE_1D_ARRAY, GL_TEXTURE_RECTANGLE, and the 6 GL_TEXTURE_CUBE_MAP* faces (of the form GL_TEXTURE_CUBE_MAP_POSITIVE/NEGATIVE_X/Y/Z). <code>glTexImage1D</code> can only be used with GL_TEXTURE_1D.
==== Mipmap completeness ====


The two multisample <code>glTexImage*</code> functions can only be used with GL_TEXTURE_2D_MULTISAMPLE, and GL_TEXTURE_2D_MULTISAMPLE_ARRAY, with the array version for the 3D version. These functions set the sample count in addition to the internal format and size of the texture.
Mipmap completeness essentially requires that there is consistency between the image formats of the allocated mipmap levels, the [[#Parameters|texture parameters]], and the [[#Sampling parameters|texture's sampling parameters]].


The ''internalformat'' value is the [[Image Formats|format]] of the texture. Take care with this value when allocating mipmaps: this parameter ''must'' be the same for each of the subsequent calls.
Textures that use storage allocated with [[Immutable Storage Texture|immutable storage functions]] (and [[Buffer Texture]]s) will ''always'' be mipmap complete. For other textures, the following rules apply.


The ''border'' parameter is for old, deprecated functionality. Any value other than 0 is an error.
If the [[Texture Filtering|texture's sampling parameter]] {{enum|GL_TEXTURE_MIN_FILTER}} specifies that it uses mipmaps, then the following must all be true:


The ''format'', ''type'', and ''data'' parameters are used for performing a [[Pixel Transfer]] operation. This allows one to create a texture and fill it with some data in one call. However, since you can only give it data for one mipmap, this is not as useful as expected. As with any pixel transfer operation, [[Pixel Buffer Objects]] can be used to feed OpenGL the data.
* Each mipmap level must use the ''exact same'' [[Image Format|internal format]].
* Each allocated mipmap level must have a consistent size, relative to the one before it. The width/height/depth of a mipmap level is the width/height/depth of the base level / 2<sup>''k''</sup>, where ''k'' is the mipmap level (remember: 0 is the base level). Remember to ''round down'', and that the minimum size is 1.
** 1D [[Array Textures]] have a {{param|width}} and {{param|height}}. But the {{param|height}} specifies the number of array layers in the array of 1D textures. Therefore, the {{param|height}} ''does not change'' with mipmap levels. Each mipmap level uses the same {{param|height}}. The same goes for 2D Array textures and Cubemap Array textures with the {{param|depth}} parameter.
* The [[#Mipmap range|mipmap range]] texture parameters are given values where {{enum|GL_TEXTURE_BASE_LEVEL}} <= {{enum|GL_TEXTURE_MAX_LEVEL}}.
* The base and max levels must only specify mipmap levels that have been allocated, in accord with the above.


You do not need to fill in the texture's data in the same call that you create it in. If ''data'' is NULL, no pixel transfer will be done, and the texture's data is undefined. You should make sure to fill in the texture's data at some point in the future.
Mipmap completion only applies if the minification filtering parameters use mipmaps. If it does not, then the texture is always mipmap complete.


The multisample versions of these functions do not offer pixel transfer. This is because the image data of multisample textures cannot be updated from client data. It can only be filled in as a render target, and it can only be sourced as a texture from [[GLSL]].
==== Cubemap completeness ====


=== Texture Parameters ===
[[Cubemap Texture]]s have additional requirements, due to how they are allocated (with mutable storage functions). Textures that use storage allocated with immutable storage functions will ''always'' be cubemap complete. For other textures, the following rules apply:
 
Texture objects have parameters. These parameters control many aspects of how the texture functions.


Texture parameters are set with the following functions:
* For each mipmap level, each face of a cubemap must have the same size. And that size must be square.
* For each mipmap level, each face of a cubemap must have the same internal format.


  void glTexParameter[if]( GLenum ''target'', GLenum ''pname'', T ''param'');
==== Image format completeness ====
  void glTexParameter[if]v( GLenum ''target'', GLenum ''pname'', T *''params'' );
  void glTexParameterI[i ui]v( GLenum ''target'', GLenum ''pname'', T *''params'' );


These function set the parameter values ''param'' or ''params'' for the particular texture parameter ''pname'' in the texture bound to ''target''.
The [[Image Format|internal format]] a texture uses can also affect its completeness, depending on its sampling parameters.


=== Mipmap range ===
Integer color formats and stencil index formats (whether {{enum|GL_STENCIL_INDEX}} directly or via [[Stencil Texturing]]) do not support linear filtering. As such, the {{enum|GL_TEXTURE_MAG_FILTER}} sampling parameter must be {{enum|GL_NEAREST}}, and {{enum|GL_TEXTURE_MIN_FILTER}} must be either {{enum|GL_NEAREST}} or {{enum|GL_NEAREST_MIPMAP_NEAREST}}.


The texture parameters GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL (integer values) define the closed mipmap range of mipmaps that are to be considered available with this texture. Nothing can cause the sampling of mipmaps smaller than GL_TEXTURE_BASE_LEVEL and nothing can cause the sampling of mipmaps greater than GL_TEXTURE_MAX_LEVEL. This even filters into [[GLSL]]; the texture size functions will retrieve the size of GL_TEXTURE_BASE_LEVEL, rather than the size of mipmap level 0.
==== Sampler objects and completeness ====


There is another pair of texture parameters, GL_TEXTURE_MAX_LOD and GL_TEXTURE_MIN_LOD (floating-point values). These do something similar: they clamp the value that computes which mipmap should be sampled from in a texture. However it does not cover everything; that is not the purpose of these parameters. So if your intent is to guarantee that you can never sample any other mipmap levels, what you want are the BASE_LEVEL and MAX_LEVEL, not the LODs here.
When using a texture with a [[Sampler Object]], the completeness of that texture will be based on the sampler object's sampling parameters, rather than the [[#Sampling parameters|internal sampling parameters]] of the texture.


Remember: these parameters work for the ''entire'' texture. So all cubemap faces must have the same mipmaps defined, as must all array textures.
For example, if a texture object only has the base mipmap, and the [[#Mipmap range|mipmap range parameters]] permit accessing beyond the base level, that texture object will be incomplete if the {{enum|GL_TEXTURE_MIN_FILTER}} parameters require access to mipmaps other than the base level. However, if you pair this object with a sampler who's min filter is {{enum|GL_LINEAR}} or {{enum|GL_NEAREST}}, then that texture image unit will be mipmap complete.


=== Automatic mipmap generation ===
Similarly, if a texture uses an integer [[Image Format]], and the paired sampler only uses nearest filtering, the texture will be image format complete.


It is often useful to auto-generate a mipmap set from just the base mipmap level in the previously defined range. How exactly the implementation does filtering for mipmap generation is implementation-dependent. You do not have to call the <code>glTexImage*</code> functions to allocate storage for the mipmaps to be generated; OpenGL will handle that detail for you.
So a texture may be considered complete or not, based on where it is used.


Before you can generate mipmaps, you must set the base mipmap level as above. And you must actually put data in that level. If you are generating mipmaps for cubemaps, you must have put data into all 6 faces of the cubemap.
[[Image Load Store]] does not use sampler objects. But it still performs texture completeness checks. So it will apply the completeness rules based on the [[#Sampling parameters|texture's internal sampling parameters]], not those of a sampler object.


Then, call this function:
== Storage ==
{{main|Texture Storage}}


  void glGenerateMipmap( GLenum ''target'' );
Texture objects come in three parts: storage, sampling parameters, and texture parameters. There are ''numerous'' functions to create a texture's storage; so many that the article needs its own page to describe them all.


This will cause the texture bound to ''target'' to have its mipmap levels below the base level auto-generated. The base level and max level range is observed; the base level will not change, and all levels below it will be generated, down to the max level. Any mipmap levels defined outside of the base/max range will ''not'' be changed.
== Parameters ==


=== Texture image modification ===
Texture objects have parameters. These parameters control many aspects of how the texture functions.


It is often useful to modify a texture after it is specified. If you wish to pass it data from the CPU, calling the <code>glTexImage*</code> is a very heavyweight operation. If you only want to update a subsection of the texture, those functions will not help.
Texture parameters are set with the following functions:


These functions are used to modify image data without reallocating it.
{{funcdef|
void {{apifunc|glTexParameter|[if]}}( GLenum {{param|target}}, GLenum {{param|pname}}, T {{param|param}});


  void glTexSubImage1D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLsizei ''width'', GLenum ''format'', GLenum ''type'', void *''data'' );
void {{apifunc|glTexParameter|[if]v}}( GLenum {{param|target}}, GLenum {{param|pname}}, T *{{param|params}} );
  void glTexSubImage2D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLint ''yoffset'', GLsizei ''width'', GLsizei ''height'', GLenum ''format'', GLenum ''type'', void *''data'' );
  void glTexSubImage3D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLint ''yoffset'', GLint ''zoffset'', GLsizei ''width'', GLsizei ''height'', GLsizei ''depth'', GLenum ''format'', GLenum ''type'', void *''data'' );


These functions update a specific region of the given texture and mipmap level with new data. The ''xoffset'', ''yoffset'', ''zoffset'', ''width'', ''height'', and ''depth'' define the region to be updated. The ''format'', ''type'', and ''data'' functions operate as for any [[Pixel Transfer]] operation.
void {{apifunc|glTexParameter|I[i ui]v}}( GLenum {{param|target}}, GLenum {{param|pname}}, T *{{param|params}} );
}}


=== Compressed textures ===
These function set the parameter values {{param|param}} or {{param|params}} for the particular parameter {{param|pname}} in the texture bound to {{param|target}}.


Standard [[Pixel Transfer]] operations can convert pixel data into compressed formats for you. These algorithms tend to be optimized for speed rather than image quality. Therefore, it is often desirable to pre-compress image data offline and upload it as compressed image data. A normal pixel transfer operation cannot handle this.
In the anatomy of a texture object image above, it shows three pieces of data: [[Texture Storage]], texture parameters, and [[Sampling Parameter|sampling parameters]]. It's important to understand that both of the last two kinds of data are set by the ''same functions'' for textures. Certain parameters are about the texture itself, and some are about sampling from them.


To perform such an operation, you must use the following functions:
This section will describe the texture parameters only.


  void CompressedTexImage1D( GLenum ''target'', GLint ''level'', GLenum ''internalformat'', GLsizei ''width'', GLint ''border'', GLsizei ''imageSize'', void *''data'' );
=== Mipmap range ===
  void CompressedTexImage2D( GLenum ''target'', GLint ''level'', GLenum ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLint ''border'', GLsizei ''imageSize'', void *''data'' );
  void CompressedTexImage3D( GLenum ''target'', GLint ''level'', GLenum ''internalformat'', GLsizei ''width'', GLsizei ''height'', GLsizei ''depth'', GLint ''border'', GLsizei ''imageSize'', void *''data'' );
  void CompressedTexSubImage1D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLsizei ''width'', GLenum ''format'', GLsizei ''imageSize'', void *''data'' );
  void CompressedTexSubImage2D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLint ''yoffset'', GLsizei ''width'', GLsizei ''height'', GLenum ''format'', GLsizei ''imageSize'', void *''data'' );
  void CompressedTexSubImage3D( GLenum ''target'', GLint ''level'', GLint ''xoffset'', GLint ''yoffset'', GLint ''zoffset'', GLsizei ''width'', GLsizei ''height'', GLsizei ''depth'', GLenum ''format'', GLsizei ''imageSize'', void *''data'' );


The <code>glCompressedTexImage</code> functions work very much like the <code>glTexImage</code> functions. They respecify a mipmap layer completely. The <code>glCompressedTexSubImage</code> functions work like the <code>glTexSubImage</code>, updating only the image data.
The parameters {{enum|GL_TEXTURE_BASE_LEVEL}} and {{enum|GL_TEXTURE_MAX_LEVEL}} (integer values) define the closed range of the mipmaps that are to be considered available with this texture. Nothing can cause the sampling of mipmaps smaller than {{enum|GL_TEXTURE_BASE_LEVEL}} and nothing can cause the sampling of mipmaps greater than {{enum|GL_TEXTURE_MAX_LEVEL}}. This even filters into [[GLSL]]; the texture size functions will retrieve the size of {{enum|GL_TEXTURE_BASE_LEVEL}}, rather than the size of mipmap level 0.


The ''target'', ''level'', ''xoffset'', ''yoffset'', ''zoffset'', ''width'', ''height'', ''depth'', and ''border'' fields function exactly as they did in the earlier functions. ''imageSize'' is the length of the byte array ''data''. Since the format of the compressed image data must match the specific format of the texture, the implementation can deduce what this data means from the pointer and size alone.
Note that [[Immutable Storage Texture|immutable storage textures]] will already have these values set to the mipmap range of the storage upon creation. You can set them to be some subrange of this, but it is an [[OpenGL Error|error]] to set the base or max level outside of the available mipmap range for the immutable storage.


The ''internalformat'' parameter ''must'' refer to a specific compressed format. The generic formats cannot be used here. And it is an error to call any of the <code>glCompressedTexSubImage</code> formats on a texture that doesn't use a non-generic compressed format.
=== Swizzle mask ===
{{ infobox feature
| name = Texture Swizzle
| core = 3.3
| arb_extension = [http://www.opengl.org/registry/specs/ARB/texture_swizzle.txt ARB_texture_swizzle]
| ext_extension = [http://www.opengl.org/registry/specs/EXT/texture_swizzle.txt EXT_texture_swizzle]
}}


Though this is not technically a pixel transfer operations, a buffer bound to GL_UNPACK_BUFFER can still be used in place of a client memory pointer.
While GLSL shaders are perfectly capable of reordering the {{code|vec4}} value returned by a texture function, it is often more convenient to control the ordering of the data fetched from a texture from code. This is done through swizzle parameters.


== Texture image units ==
Texture objects can have swizzling parameters. This only works for textures with color image formats. Each of the four output components, RGBA, can be set to come from a particular color channel. The swizzle mask is respected by all shader read accesses, whether via [[Sampler (GLSL)|texture samplers]] or [[Image Load Store]].


Binding textures in OpenGL is a little weird. There are two reasons to bind a texture object to the context: to change values in the object and to render something with it.
{{note|This feature only applies to reads from the shader. Writes via [[Image Load Store]] are not affected by the swizzle mask. Also, are reads or writes from other sources, such as [[Blending]] operations, do not respect the swizzle mask.}}


Changing the texture's stored state can be done with the above simple <code>glBindTexture</code> call. However, actually rendering with a texture is a bit more complicated.
To set the output for a component, you would set the {{enum|GL_TEXTURE_SWIZZLE_'''C'''}} texture parameter, where '''C''' is R, G, B, or A. These parameters can be set to the following values:


A texture can be bound to one or more locations. These locations are called ''texture image units''. OpenGL contexts have a maximum number of texture image units, queriable from the constant GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
* {{enum|GL_RED}}: The value for this component comes from the red channel of the image. All color formats have at least a red channel.
* {{enum|GL_GREEN}}: The value for this component comes from the green channel of the image, or 0 if it has no green channel.
* {{enum|GL_BLUE}}: The value for this component comes from the blue channel of the image, or 0 if it has no blue channel.
* {{enum|GL_ALPHA}}: The value for this component comes from the alpha channel of the image, or 1 if it has no alpha channel.
* {{enum|GL_ZERO}}: The value for this component is always 0.
* {{enum|GL_ONE}}: The value for this component is always 1.


What image unit a <code>glBindTexture</code> call binds the texture to depends on the current active texture image unit. This value is set by calling:
You can also use the {{enum|GL_TEXTURE_SWIZZLE_RGBA}} parameter to set all four at once. This one takes an array of four values. For example:


  void glActiveTexture( GLenum ''texture'' );
<source lang="cpp">
// Bind the texture 2D.
GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
</source>


The value of ''texture'' is GL_TEXTURE0 + ''i'', where ''i'' is a number on the half-open range [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS). This will cause the texture image unit ''i'' to be the current active image unit.
This will effectively map the red channel in the image to the alpha channel when the shader accesses it.


Each texture image unit supports bindings to all targets. So a 2D texture and an array texture can be bound to the same image unit, or different 2D texture can be bound in two different image units without affecting each other. So which texture gets used when rendering? In [[GLSL]], this depends on the type of sampler that uses this texture image unit.
=== Stencil texturing ===
{{infobox feature
| name = Stencil Texturing
| core = 4.3
| core_extension = {{extref|stencil_texturing}}
}}


{{note|This sounds suspiciously like you can use the same texture image unit for different samplers, as long as they have different texture types. ''Do not do this.'' This is a corner case in the spec and implementations may not implement it properly. It is safer to simply let each sampler have its own texture image unit.}}
A texture with a depth image format is normally considered a depth component texture. This means that non-depth comparison access will return a single floating-point value (as depth components are either normalized integers or floats). Depth textures in this way can be considered a special form of single-channel floating-point color textures.


The <code>glActiveTexture</code> function will affect the functioning of any function that takes a texture ''target'' as a parameter.
However, if the texture uses a [[Depth Stencil Format|packed depth/stencil image format]], it is possible to access the stencil component ''instead'' of the depth component. This is controlled by the parameter {{enum|GL_DEPTH_STENCIL_TEXTURE_MODE}}.


== Texture sampling ==
When the parameter is set to {{enum|GL_DEPTH_COMPONENT}}, then accessing it from the shader will access the depth component as a single float, as normal. But when the parameter is set to {{enum|GL_STENCIL_INDEX}}, the shader can access the stencil component.


Sampling is the process of fetching a value from a texture at a given position. [[GLSL Samplers|GLSL]] controls much of the process of sampling, but there are many texture parameters that affect this as well.
This parameter changes the very nature of the texture access. The stencil component is an ''unsigned integer'' value, so you must use an [[Sampler (GLSL)|unsigned integer sampler]] when accessing it. So when accessing the stencil component of a 2D depth/stencil texture, you must use {{code|usampler2D}}.


=== Normalized texture coordinates ===
{{note|Though this parameter affects sampling, it is not a ''sampling parameter''. As such, you cannot bind the same texture object to two image units and use two different sampler objects to fetch the depth and stencil components. However, you ''can'' create a [[View texture|view of the texture]] (both view textures and stencil texturing are GL 4.3 features), and set different texture parameters into the different views. One view for the depth, one view for the stencil.}}


Locations in a texture are usually abstracted via the use of normalized texture coordinates. These are floating-point values where 0 means one edge of the texture and 1 means the opposite edge of the texture. This abstracts away the size of the texture, allowing different textures with different sizes to be used.
== Sampling parameters ==
{{main|Sampler Object#Sampling parameters}}


=== Filtering ===
Sampling is the process of fetching a value from a texture at a given position. [[Sampler (GLSL)|GLSL]] controls much of the process of sampling, but there are many values associated with the texture object that can affect this as well.


Filtering is the process of accessing a particular sample from a texture. There are two cases for filtering: minification and magnification. Magnification means that the area of the fragment in texture space is smaller than a texel, and minification means that the area of the fragment in texture space is larger than a texel. Filtering for these two cases can be set independently.
These parameters are shared with [[Sampler Object]]s, in that both texture objects and sampler objects have them. If a texture is used with a sampler object, all of the parameters from the sampler object override those set by the texture object.


The magnification filter is controlled by the GL_TEXTURE_MAG_FILTER texture parameter. This value can be GL_LINEAR or GL_NEAREST. If GL_NEAREST is used, then the implementation will select the texel nearest the texture coordinate; this is commonly called "point sampling"). If GL_LINEAR is used, the implementation will perform a weighted linear blend between the nearest adjacent samples.
== Texture image units ==
 
The minification filter is controlled by the GL_TEXTURE_MIN_FILTER texture parameter. To understand these values better, it is important to discuss what the particular options are.
 
When doing minification, you can choose to use mipmapping or not. Using mipmapping means selecting between multiple mipmaps based on the angle and size of the texture relative to the screen. Whether you use mipmapping or not, you can still select between linear blending of the particular layer or nearest. And if you do use mipmapping, you can choose to either select a single mipmap to sample from, or you can sample the two adjacent mipmaps and linearly blend the resulting values to get the final result.
 
The OpenGL minification settings for these are as follows:


{| class="wikitable" border="1"
Much like with [[Buffer Object]]s and [[Buffer Object#Binding indexed targets|indexed targets]], a texture can be bound to one or more locations for rendering. These locations are called ''texture image units''. OpenGL contexts have a maximum number of texture image units, queryable from the constant {{enum|GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS}}.
|-
! Param Setting
! Linear within mip-level
! Has mipmapping
! Linear between mip-levels
|-
| GL_NEAREST
| No
| No
|
|-
| GL_LINEAR
| Yes
| No
|
|-
| GL_NEAREST_MIPMAP_NEAREST
| No
| Yes
| No
|-
| GL_LINEAR_MIPMAP_NEAREST
| Yes
| Yes
| No
|-
| GL_NEAREST_MIPMAP_LINEAR
| No
| Yes
| Yes
|-
| GL_LINEAR_MIPMAP_LINEAR
| Yes
| Yes
| Yes
|}


A note on terminology. This discussion has refrained from using the common filtering terms "bilinear" and "trilinear." This is for a good reason; these terms are often misunderstood and do not carry over to all texture types.
Textures can be bound to these textures units with this function:


Take the term "bilinear". This term is used because it refers to linear filtering in 2 axes: horizontally and vertically in a 2D texture. A monolinear would be filtering in one axis, and thus trilinear is filtering in 3 axes.
{{funcdef|void {{apifunc|glBindTextureUnit}}(GLuint {{param|unit}}, GLuint {{param|texture}});}}


The problem is that what constitutes "bilinear" depends on the texture type. Or specifically, its dimensionality. Setting GL_TEXTURE_MAG_FILTER and MIN_FILTERs to GL_LINEAR will create monolinear filtering in a 1D texture, bilinear filtering in a 2D texture, and trilinear in a 3D texture. In all cases, it is simply doing a linear filter between the nearest samples; some texture types simply have more nearest samples than others.
Where {{param|unit}} is the 0-indexed texture unit you'd like to bind to, and {{param|texture}} is the texture object you'd like to bind there (or zero to unbind it).


Unfortunately, what most people think of as "trilinear" is not linear filtering of a 3D texture, but what in OpenGL terms is GL_LINEAR mag filter and GL_LINEAR_MIPMAP_LINEAR in the min filter in a 2D texture. That is, it is bilinear filtering of each appropriate mipmap level, and doing a third linear filter between the adjacent mipmap levels. Hence the term "trilinear".
{{apifunc|glBindTextureUnit}} is a [[Direct State Access|DSA]] function, so if you don't have access to this you can also use the older ''active texture unit'' API:


This is easily confused with what is just GL_LINEAR for 3D textures. That is why OpenGL and this discussion does not use these terms.
{{funcdef|void {{apifunc|glActiveTexture}}(GLenum {{param|texture}});}}


==== Anisotropic filtering ====
Which specifies which texture unit a {{apifunc|glBindTexture}} call should bind the texture object to, ''and'' defines the ''active texture unit'' that any subsequent function that takes a texture ''target'' should use.
{{param|texture}} isn't a simple index as in {{apifunc|glBindTextureUnit}}, but one of a consecutive set of enums starting from {{enum|GL_TEXTURE0}} - commonly written as {{code|GL_TEXTURE0 + {{param|unit}}}}.


{{note|This is not core behavior; it is governed by the extension GL_EXT_texture_filter_anisotropic. However, this extension is available [[Ubiquitous Extensions|virtually everywhere]].}}
Put simply, where with [[Direct State Access|DSA]] you would write:


Anisotropic filtering is an advanced filtering technique that takes more than one sample point and blends them together. Exactly how this is done is implementation-dependent, but the control is a specific value: the maximum number of samples that can be taken of the texture. More samples may slow down performance, but increase image quality. Then again, it may not, depending on the angle you're looking at the surface. Implementations only take extra samples when ''needed''.
<source lang="cpp">
glBindTextureUnit(0, texture1);
glBindTextureUnit(1, texture2);
glBindTextureUnit(2, texture3);
</source>


To use anisotropic filtering, set the GL_TEXTURE_MAX_ANISOTROPY_EXT parameter. This parameter is floating-point, and can be set between 1.0f and an implementation-defined maximum anisotropy (queried with GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT). Any value greater than 1.0f counts as a use of anisotropic filtering.
You would instead previously have written:


Anisotropic filtering is not a replacement for mipmaps or mipmap filtering. For best results, combine a anisotropic filtering with a GL_LINEAR_MIPMAP_LINEAR minification filter.
<source lang="cpp">
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1);


=== Comparison mode ===
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, texture2);


=== Edge value sampling ===
glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, texture3);
</source>


Normalized texture coordinates are not limited to values between 0.0 and 1.0. They can be any floating-point number. When a texture coordinate is not within the [0, 1] range, a heuristic must be employed to decide what the color value will be.
Noting that not only are there more calls and that there's some strangeness around {{enum|GL_TEXTURE0}}s usage, but that you also must ensure to bind to the correct {{param|target}} as well. {{apifunc|glBindTextureUnit}} not only combines these calls, but derives the correct targets from the texture objects you bind, avoiding potential errors.


Each dimension of a texture can have a different heuristic. These are set by setting the texture parameters GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, and GL_TEXTURE_WRAP_R, where S, T, and R are the first 3 texture coordinates in order. The possible heuristics are:
Each texture image unit supports bindings to all targets. So a 2D texture and an array texture can be bound to the same image unit, or different 2D textures can be bound in two different image units without affecting each other. So which texture gets used when rendering? In [[GLSL Sampler|GLSL]], this depends on the type of sampler that uses this texture image unit.


* GL_REPEAT: the texture coordinate wraps around the texture. So a texture coordinate of -0.2 becomes the equivalent of 0.8.
{{note|This sounds suspiciously like you can use the same texture image unit for different samplers, as long as they have different texture types. ''Do not do this.'' The spec explicitly disallows it; if two different GLSL samplers have different texture types, but are associated with the same texture image unit, then rendering will fail. Give each sampler a different texture image unit.}}
* GL_MIRRORED_REPEAT: the texture coordinate wraps around like a mirror. -0.2 becomes 0.2, -1.2 becomes 0.8, etc.
* GL_CLAMP_TO_EDGE: the texture coordinate is clamped to the [0, 1] range.
* GL_CLAMP_TO_BORDER: the texture coordinate is clamped to the [0, 1] range, but the edge texels are blended with a constant border color.


== GLSL binding ==
== GLSL binding ==


Programs are one of the two users of textures. In order to use textures with a program, the program itself must use certain syntax to expose texture binding points.
Shader programs are one of two uses of textures. In order to use textures with a program, the program itself must use certain syntax to expose texture binding points.


=== Samplers ===
=== Samplers ===
{{main|GLSL Samplers}}
{{main|Sampler (GLSL)}}


A ''sampler'' in [[GLSL]] is a uniform variable that represents an accessible texture. It cannot be set from within a program; it can only be set by the user of the program. Sampler types correspond to OpenGL texture types.
A ''sampler'' in [[GLSL]] is a uniform variable that represents an accessible texture. It cannot be set from within a program; it can only be set by the user of the program. Sampler types correspond to OpenGL texture types.
Line 264: Line 246:
Samplers are used with GLSL texture access functions.
Samplers are used with GLSL texture access functions.


=== Programs and textures ===
[[Use Texture With Shader|The process of using textures with program samplers]] involves 2 halves. Texture objects are not directly associated with or attached to program objects. Instead, program samplers reference texture image unit indices. Whatever textures are bound to those image units at the time of rendering are used by the program.
{{main|GLSL Samplers#Binding textures to samplers}}
 
So the first step is to set the [[GLSL Uniforms|uniform]] value for the program samplers. For each sampler uniform, set its uniform value to an integer on the range [0, {{enum|GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS}}). When the time comes to use the program directly, simply use {{apifunc|glActiveTexture}} and {{apifunc|glBindTexture}} to bind the textures of interest to these image units.


The process of using textures with a program involves 2 halves. Texture objects are not directly associated with or attached to programs. Instead, program samplers reference texture image unit indices. And whatever textures are bound to those image units at the time of rendering are used by the program.
The textures bound to the image unit set in the sampler uniforms must match the sampler's type. So a {{code|sampler1D}} will look to the {{enum|GL_TEXTURE_1D}} binding in the image unit it is set in.


So the first step is to set the [[GLSL Uniforms|uniform]] value for the program samplers. For each sampler uniform, set its uniform value to an integer on the range [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS). When the time comes to use the program directly, simply use <code>glActiveTexture</code> and <code>glBindTexture</code> to bind the textures of interest to these image units.
If a [[Sampler Object]] is bound to the same texture image unit as a texture, then the sampler object's [[Sampling Parameter|parameters]] will ''replace'' the sampling parameters from that texture object.


The textures bound to the image unit set in the sampler uniforms must match the sampler's type. So a <code>sampler1D</code> will look to the GL_TEXTURE_1D binding in the image unit it is set in.
=== Images ===
{{main|Image Load Store}}


== Rendet targets ==
Images within a texture can be used for arbitrary image load/store operations. This is done via ''image variables'', which are declared as uniforms. [[Image Type|Image uniforms]] are associated with an image unit (different from a ''texture'' image unit). The association works similarly as for sampler uniforms, only the number of image units per shader stage is different from the number of texture image units per shader stage.
 
Images are bound to image units with {{apifunc|glBindImageTexture}}.
 
== Render targets ==
{{main|Framebuffer Objects}}
{{main|Framebuffer Objects}}


Through the use of a framebuffer object, individual images within a texture can be the destination for rendering.
Through the use of a framebuffer object, individual images within a texture can be the destination for rendering.
== Reference ==
* [[:Category:Core API Ref Texturing‎]]: Reference documentation for all functions related to textures and [[Sampler Object|sampler objects]].


[[Category:Objects]]
[[Category:Objects]]
[[Category:Textures]]
[[Category:Textures]]
[[Category:Missing DSA]]

Latest revision as of 11:09, 1 August 2024

A texture is an OpenGL Object that contains one or more images that all have the same image format. A texture can be used in two ways: it can be the source of a texture access from a Shader, or it can be used as a render target.

Theory

For the purpose of this discussion, an image is defined as a single array of pixels of a certain dimensionality (1D, 2D, or 3D), with a particular size, and a specific format.

A texture is a container of one or more images. But textures do not store arbitrary images; a texture has specific constraints on the images it can contain. There are three defining characteristics of a texture, each of them defining part of those constraints: the texture type, texture size, and the image format used for images in the texture. The texture type defines the arrangement of images within the texture. The size defines the size of the images in the texture. And the image format defines the format that all of these images share.

There are a number of different types of textures. These are:

  • GL_TEXTURE_1D: Images in this texture all are 1-dimensional. They have width, but no height or depth.
  • GL_TEXTURE_2D: Images in this texture all are 2-dimensional. They have width and height, but no depth.
  • GL_TEXTURE_3D: Images in this texture all are 3-dimensional. They have width, height, and depth.
  • GL_TEXTURE_RECTANGLE: The image in this texture (only one image. No mipmapping) is 2-dimensional. Texture coordinates used for these textures are not normalized.
  • GL_TEXTURE_BUFFER: The image in this texture (only one image. No mipmapping) is 1-dimensional. The storage for this data comes from a Buffer Object.
  • GL_TEXTURE_CUBE_MAP: There are exactly 6 distinct sets of 2D images, each image being of the same size and must be of a square size. These images act as 6 faces of a cube.
  • GL_TEXTURE_1D_ARRAY: Images in this texture all are 1-dimensional. However, it contains multiple sets of 1-dimensional images, all within one texture. The array length is part of the texture's size.
  • GL_TEXTURE_2D_ARRAY: Images in this texture all are 2-dimensional. However, it contains multiple sets of 2-dimensional images, all within one texture. The array length is part of the texture's size.
  • GL_TEXTURE_CUBE_MAP_ARRAY: Images in this texture are all cube maps. It contains multiple sets of cube maps, all within one texture. The array length * 6 (number of cube faces) is part of the texture size.
  • GL_TEXTURE_2D_MULTISAMPLE: The image in this texture (only one image. No mipmapping) is 2-dimensional. Each pixel in these images contains multiple samples instead of just one value.
  • GL_TEXTURE_2D_MULTISAMPLE_ARRAY: Combines 2D array and 2D multisample types. No mipmapping.


Texture sizes have a limit based on the GL implementation. For 1D and 2D textures (and any texture types that use similar dimensionality, like cubemaps) the max size of either dimension is GL_MAX_TEXTURE_SIZE. For array textures, the maximum array length is GL_MAX_ARRAY_TEXTURE_LAYERS. For 3D textures, no dimension can be greater than GL_MAX_3D_TEXTURE_SIZE in size.

Within these limits, the size of a texture can be any value. It is advised however, that you stick to powers-of-two for texture sizes, unless you have a significant need to use arbitrary sizes.

Mip maps

When a texture is directly applied to a surface, how many pixels of that texture (commonly called "texels") are used depends on the angle at which that surface is rendered. A texture mapped to a plane that is almost edge-on with the camera will only use a fraction of the pixels of the texture. Similarly, looking directly down on the texture from far away will show fewer texels than an up-close version.

The problem is with animation. When you slowly zoom out on a texture, you start to see aliasing artifacts appear. These are caused by sampling fewer than all of the texels; the choice of which texels are sampled changes between different frames of the animation. Even with linear filtering (see below), artifacts will appear as the camera zooms out.

To solve this problem, we employ mip maps. These are pre-shrunk versions of the full-sized image. Each mipmap is half the size (rounded down) of the previous one in the chain, continuing until all dimensions are 1. So a 64x16 2D texture can have 6 mip-maps: 32x8, 16x4, 8x2, 4x1, 2x1, and 1x1. OpenGL does not require that the entire mipmap chain is complete; you can specify what range of mipmaps in a texture are available.

Note that the division by 2 rounds down. So a 63x63 texture has as its next lowest mipmap level 31x31. And so on.

The base level of a mipmap chain is the largest one in size. It is also the one that defines the full size of the texture. OpenGL numbers this mipmap level as 0; the next largest mipmap level is 1, and so on.

Some texture types have multiple conceptually independent sets of mipmaps. Each face of a cubemap has its own set of mipmaps, as does each entry in an array texture. However, while the chains are conceptually independent, there is only one mipmap setting per-texture. So all of the mipmap chains in a texture must have the same number of mipmaps.

When sampling a texture (see below), the implementation will automatically select which mipmap to use based on the viewing angle, size of texture, and various other factors.

The base level of a texture does not have to be loaded. The valid range of mipmaps must be contiguous, but the range need not start at 0.

Texture Objects

Anatomy of a Texture
Diagram of the contents of a texture object

Textures in OpenGL are OpenGL Objects, and they follow the standard conventions of such. So they have the standard glGenTextures, glBindTexture, as you would expect.

The target parameter of glBindTexture corresponds to the texture's type. So when you use a freshly generated texture name, the first bind helps define the type of the texture. It is not legal to bind an object to a different target than the one it was previously bound with. So if you generate a texture and bind it as GL_TEXTURE_1D, then you must continue to bind it as such.

As with any other kind of OpenGL object, it is legal to bind multiple objects to different targets. So you can have a GL_TEXTURE_1D bound while a GL_TEXTURE_2D_ARRAY is bound.

Texture completeness

A texture object has the concept of "completeness". A complete texture object is one which is in a logical state to be used for many operations. Until a texture is complete, it *cannot* be used in shader sampling or Image Load Store operations. And attaching an image from a texture to a Framebuffer Object requires certain forms of completeness.

A texture object is complete if it fulfills the following 3 kinds of completeness requirements.

Mipmap completeness

Mipmap completeness essentially requires that there is consistency between the image formats of the allocated mipmap levels, the texture parameters, and the texture's sampling parameters.

Textures that use storage allocated with immutable storage functions (and Buffer Textures) will always be mipmap complete. For other textures, the following rules apply.

If the texture's sampling parameter GL_TEXTURE_MIN_FILTER specifies that it uses mipmaps, then the following must all be true:

  • Each mipmap level must use the exact same internal format.
  • Each allocated mipmap level must have a consistent size, relative to the one before it. The width/height/depth of a mipmap level is the width/height/depth of the base level / 2k, where k is the mipmap level (remember: 0 is the base level). Remember to round down, and that the minimum size is 1.
    • 1D Array Textures have a width​ and height​. But the height​ specifies the number of array layers in the array of 1D textures. Therefore, the height​ does not change with mipmap levels. Each mipmap level uses the same height​. The same goes for 2D Array textures and Cubemap Array textures with the depth​ parameter.
  • The mipmap range texture parameters are given values where GL_TEXTURE_BASE_LEVEL <= GL_TEXTURE_MAX_LEVEL.
  • The base and max levels must only specify mipmap levels that have been allocated, in accord with the above.

Mipmap completion only applies if the minification filtering parameters use mipmaps. If it does not, then the texture is always mipmap complete.

Cubemap completeness

Cubemap Textures have additional requirements, due to how they are allocated (with mutable storage functions). Textures that use storage allocated with immutable storage functions will always be cubemap complete. For other textures, the following rules apply:

  • For each mipmap level, each face of a cubemap must have the same size. And that size must be square.
  • For each mipmap level, each face of a cubemap must have the same internal format.

Image format completeness

The internal format a texture uses can also affect its completeness, depending on its sampling parameters.

Integer color formats and stencil index formats (whether GL_STENCIL_INDEX directly or via Stencil Texturing) do not support linear filtering. As such, the GL_TEXTURE_MAG_FILTER sampling parameter must be GL_NEAREST, and GL_TEXTURE_MIN_FILTER must be either GL_NEAREST or GL_NEAREST_MIPMAP_NEAREST.

Sampler objects and completeness

When using a texture with a Sampler Object, the completeness of that texture will be based on the sampler object's sampling parameters, rather than the internal sampling parameters of the texture.

For example, if a texture object only has the base mipmap, and the mipmap range parameters permit accessing beyond the base level, that texture object will be incomplete if the GL_TEXTURE_MIN_FILTER parameters require access to mipmaps other than the base level. However, if you pair this object with a sampler who's min filter is GL_LINEAR or GL_NEAREST, then that texture image unit will be mipmap complete.

Similarly, if a texture uses an integer Image Format, and the paired sampler only uses nearest filtering, the texture will be image format complete.

So a texture may be considered complete or not, based on where it is used.

Image Load Store does not use sampler objects. But it still performs texture completeness checks. So it will apply the completeness rules based on the texture's internal sampling parameters, not those of a sampler object.

Storage

Texture objects come in three parts: storage, sampling parameters, and texture parameters. There are numerous functions to create a texture's storage; so many that the article needs its own page to describe them all.

Parameters

Texture objects have parameters. These parameters control many aspects of how the texture functions.

Texture parameters are set with the following functions:

void glTexParameter[if]( GLenum target​, GLenum pname​, T param​);

void glTexParameter[if]v( GLenum target​, GLenum pname​, T *params​ );

void glTexParameterI[i ui]v( GLenum target​, GLenum pname​, T *params​ );

These function set the parameter values param​ or params​ for the particular parameter pname​ in the texture bound to target​.

In the anatomy of a texture object image above, it shows three pieces of data: Texture Storage, texture parameters, and sampling parameters. It's important to understand that both of the last two kinds of data are set by the same functions for textures. Certain parameters are about the texture itself, and some are about sampling from them.

This section will describe the texture parameters only.

Mipmap range

The parameters GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL (integer values) define the closed range of the mipmaps that are to be considered available with this texture. Nothing can cause the sampling of mipmaps smaller than GL_TEXTURE_BASE_LEVEL and nothing can cause the sampling of mipmaps greater than GL_TEXTURE_MAX_LEVEL. This even filters into GLSL; the texture size functions will retrieve the size of GL_TEXTURE_BASE_LEVEL, rather than the size of mipmap level 0.

Note that immutable storage textures will already have these values set to the mipmap range of the storage upon creation. You can set them to be some subrange of this, but it is an error to set the base or max level outside of the available mipmap range for the immutable storage.

Swizzle mask

Texture Swizzle
Core in version 4.6
Core since version 3.3
ARB extension ARB_texture_swizzle
EXT extension EXT_texture_swizzle

While GLSL shaders are perfectly capable of reordering the vec4 value returned by a texture function, it is often more convenient to control the ordering of the data fetched from a texture from code. This is done through swizzle parameters.

Texture objects can have swizzling parameters. This only works for textures with color image formats. Each of the four output components, RGBA, can be set to come from a particular color channel. The swizzle mask is respected by all shader read accesses, whether via texture samplers or Image Load Store.

Note: This feature only applies to reads from the shader. Writes via Image Load Store are not affected by the swizzle mask. Also, are reads or writes from other sources, such as Blending operations, do not respect the swizzle mask.

To set the output for a component, you would set the GL_TEXTURE_SWIZZLE_C texture parameter, where C is R, G, B, or A. These parameters can be set to the following values:

  • GL_RED: The value for this component comes from the red channel of the image. All color formats have at least a red channel.
  • GL_GREEN: The value for this component comes from the green channel of the image, or 0 if it has no green channel.
  • GL_BLUE: The value for this component comes from the blue channel of the image, or 0 if it has no blue channel.
  • GL_ALPHA: The value for this component comes from the alpha channel of the image, or 1 if it has no alpha channel.
  • GL_ZERO: The value for this component is always 0.
  • GL_ONE: The value for this component is always 1.

You can also use the GL_TEXTURE_SWIZZLE_RGBA parameter to set all four at once. This one takes an array of four values. For example:

// Bind the texture 2D.
GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);

This will effectively map the red channel in the image to the alpha channel when the shader accesses it.

Stencil texturing

Stencil Texturing
Core in version 4.6
Core since version 4.3
Core ARB extension ARB_stencil_texturing

A texture with a depth image format is normally considered a depth component texture. This means that non-depth comparison access will return a single floating-point value (as depth components are either normalized integers or floats). Depth textures in this way can be considered a special form of single-channel floating-point color textures.

However, if the texture uses a packed depth/stencil image format, it is possible to access the stencil component instead of the depth component. This is controlled by the parameter GL_DEPTH_STENCIL_TEXTURE_MODE.

When the parameter is set to GL_DEPTH_COMPONENT, then accessing it from the shader will access the depth component as a single float, as normal. But when the parameter is set to GL_STENCIL_INDEX, the shader can access the stencil component.

This parameter changes the very nature of the texture access. The stencil component is an unsigned integer value, so you must use an unsigned integer sampler when accessing it. So when accessing the stencil component of a 2D depth/stencil texture, you must use usampler2D.

Note: Though this parameter affects sampling, it is not a sampling parameter. As such, you cannot bind the same texture object to two image units and use two different sampler objects to fetch the depth and stencil components. However, you can create a view of the texture (both view textures and stencil texturing are GL 4.3 features), and set different texture parameters into the different views. One view for the depth, one view for the stencil.

Sampling parameters

Sampling is the process of fetching a value from a texture at a given position. GLSL controls much of the process of sampling, but there are many values associated with the texture object that can affect this as well.

These parameters are shared with Sampler Objects, in that both texture objects and sampler objects have them. If a texture is used with a sampler object, all of the parameters from the sampler object override those set by the texture object.

Texture image units

Much like with Buffer Objects and indexed targets, a texture can be bound to one or more locations for rendering. These locations are called texture image units. OpenGL contexts have a maximum number of texture image units, queryable from the constant GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

Textures can be bound to these textures units with this function:

void glBindTextureUnit(GLuint unit​, GLuint texture​);

Where unit​ is the 0-indexed texture unit you'd like to bind to, and texture​ is the texture object you'd like to bind there (or zero to unbind it).

glBindTextureUnit is a DSA function, so if you don't have access to this you can also use the older active texture unit API:

void glActiveTexture(GLenum texture​);

Which specifies which texture unit a glBindTexture call should bind the texture object to, and defines the active texture unit that any subsequent function that takes a texture target should use. texture​ isn't a simple index as in glBindTextureUnit, but one of a consecutive set of enums starting from GL_TEXTURE0 - commonly written as GL_TEXTURE0 + unit​.

Put simply, where with DSA you would write:

glBindTextureUnit(0, texture1);
glBindTextureUnit(1, texture2);
glBindTextureUnit(2, texture3);

You would instead previously have written:

glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, texture1);

glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_3D, texture2);

glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, texture3);

Noting that not only are there more calls and that there's some strangeness around GL_TEXTURE0s usage, but that you also must ensure to bind to the correct target​ as well. glBindTextureUnit not only combines these calls, but derives the correct targets from the texture objects you bind, avoiding potential errors.

Each texture image unit supports bindings to all targets. So a 2D texture and an array texture can be bound to the same image unit, or different 2D textures can be bound in two different image units without affecting each other. So which texture gets used when rendering? In GLSL, this depends on the type of sampler that uses this texture image unit.

Note: This sounds suspiciously like you can use the same texture image unit for different samplers, as long as they have different texture types. Do not do this. The spec explicitly disallows it; if two different GLSL samplers have different texture types, but are associated with the same texture image unit, then rendering will fail. Give each sampler a different texture image unit.

GLSL binding

Shader programs are one of two uses of textures. In order to use textures with a program, the program itself must use certain syntax to expose texture binding points.

Samplers

A sampler in GLSL is a uniform variable that represents an accessible texture. It cannot be set from within a program; it can only be set by the user of the program. Sampler types correspond to OpenGL texture types.

Samplers are used with GLSL texture access functions.

The process of using textures with program samplers involves 2 halves. Texture objects are not directly associated with or attached to program objects. Instead, program samplers reference texture image unit indices. Whatever textures are bound to those image units at the time of rendering are used by the program.

So the first step is to set the uniform value for the program samplers. For each sampler uniform, set its uniform value to an integer on the range [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS). When the time comes to use the program directly, simply use glActiveTexture and glBindTexture to bind the textures of interest to these image units.

The textures bound to the image unit set in the sampler uniforms must match the sampler's type. So a sampler1D will look to the GL_TEXTURE_1D binding in the image unit it is set in.

If a Sampler Object is bound to the same texture image unit as a texture, then the sampler object's parameters will replace the sampling parameters from that texture object.

Images

Images within a texture can be used for arbitrary image load/store operations. This is done via image variables, which are declared as uniforms. Image uniforms are associated with an image unit (different from a texture image unit). The association works similarly as for sampler uniforms, only the number of image units per shader stage is different from the number of texture image units per shader stage.

Images are bound to image units with glBindImageTexture.

Render targets

Through the use of a framebuffer object, individual images within a texture can be the destination for rendering.

Reference