Sampler Object

From OpenGL Wiki
Jump to navigation Jump to search
Sampler Object
Core in version 4.6
Core since version 3.3
Core ARB extension ARB_sampler_objects

A Sampler Object is an OpenGL Object that stores the sampling parameters for a Texture access inside of a shader.

Management[edit]

As a standard OpenGL Object, it has the usual functions: glGenSamplers, glDeleteSamplers and glIsSampler.

It also has glBindSampler, which takes a texture unit index (on the half-open range [0, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) ) and a sampler object. Unlike most other OpenGL objects however, you do not need to bind sampler objects to modify them. The functions to set state in them take sampler objects as parameters. You only bind a sampler object to a texture image unit when you wish to use it, not just to change it.

To set a parameter on a sampler object, use one of these functions below:

 void glSamplerParameter[if]( GLuint sampler​​, GLenum pname​, T param​);
 void glSamplerParameter[if]v( GLuint sampler​​, GLenum pname​, T *params​ );
 void glSamplerParameterI[i ui]v( GLuint sampler​​, GLenum pname​, T *params​ );

pname​ specifies the name of the parameter being set. param(s)​ is the value to set into that parameter. The valid pname​ parameters and params​ for them are defined below.

When a sampler object is bound to a texture image unit, the internal sampling parameters for a texture bound to the same image unit are all ignored. Instead, the sampling parameters are taken from this sampler object.

Sampling parameters[edit]

All of the following parameters can be used with the glTexParameter* set of functions. You could say that a texture object contains a sampler object, which you access through the texture interface.

Filtering[edit]

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.

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.

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:

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

Filtering textures that use the sRGB colorspace may be sRGB correct or it may not. Linear interpolation in a non-linear colorspace like sRGB will not produce correct results. The OpenGL specification recommends, but does not require that implementations covert samples to linear RGB before filtering. They may do filtering in sRGB space, then convert to linear. Generally speaking, all GL 3.x+ hardware will do filtering correctly.

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.

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.

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.

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

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.

Anisotropic filtering[edit]

Anisotropic Filtering
Core in version 4.6
Core since version 4.6
Core ARB extension ARB_texture_filter_anisotropic
EXT extension EXT_texture_filter_anisotropic
Note: Though this feature only became core in OpenGL 4.6, it is widely available through the EXT_texture_filter_anisotropic extension.

Anisotropic filtering is an advanced filtering technique that takes multiple samples, blending the results together. Exactly how this is done is implementation-dependent, but control over the feature is specific: the user provides a maximum number of samples that can be taken of the texture during any one texture fetch. Note that this is the "maximum" number of samples; a particular texture fetch may take fewer samples. Hardware generally attempts to determine the best number of samples to take, clamped to the user-provided maximum.

To use anisotropic filtering, set the GL_TEXTURE_MAX_ANISOTROPY sampling 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). Any value greater than 1.0f counts as a use of anisotropic filtering.

Anisotropic filtering is not a replacement for mipmaps or mipmap filtering. For best results, combine anisotropic filtering with a GL_LINEAR_MIPMAP_LINEAR minification filter.

LOD range[edit]

There is a pair of sampling parameters that affect the mipmap image selection: GL_TEXTURE_MAX_LOD and GL_TEXTURE_MIN_LOD (floating-point values). The way these work in mipmap selection is quite complicated; the specification goes into full detail about it. These selection clamping parameters will not cause sampling outside of the texture's mipmap range specified by GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL.

LOD bias[edit]

The mipmap image selection process can be adjusted coarsely by using the GL_TEXTURE_LOD_BIAS​ sampling parameter. This bias will be added to the mipmap LOD calculation, as well as the bias provided by one of the texture sampling functions in GLSL. This LOD calculation is used to select the mipmap level or pair of mipmap levels to sample from. A positive bias means that larger mipmaps will be selected even when the texture is viewed from farther away. This can cause visual aliasing, but in small quantities it can make textures a bit more sharp.

These selection clamping parameters will not cause sampling outside of the texture's mipmap range specified by GL_TEXTURE_BASE_LEVEL and GL_TEXTURE_MAX_LEVEL.

Comparison mode[edit]

Depth textures (textures that have a depth component image format) can be sampled in one of two ways. They can be sampled as a normal texture, which simply retrieves the depth value (with filtering applied). This will return a vec4 containing a single floating-point value.

They can also be fetched in comparison mode. This means that sampling from the texture requires a value to compare to those pulled from the texture; this value is called the reference value. The result of the comparison depends on the comparison function set in the texture. If the function succeeds, the resulting value is 1.0f; if it fails, it is 0.0f. Swizzling can be used, but only the R component of the swizzled result will be returned. So it's not very useful.

When linear filtering is used, the actual returned value is implementation-defined. However, the value will be on the range [0, 1] and will be proportional to the number of neighboring texels that pass the comparison based on the single given value. In effect, it performs linear filtering on the results of fetching from the nearest texels in the texture. This is commonly called "Percentage Closer Filtering".

If the texture is a normalized integer depth format, then the reference value is clamped to [0, 1], to match the values from the texture. Otherwise, the value is not clamped.

Using this mode requires two special settings. First, the sampler used in GLSL must be a shadow sampler. Second, the texture used in that sampler must have activated depth comparison mode. Attempting to use a texture without comparison with a shadow sampler, or vice-versa, will result in an error upon rendering.

To set the texture to comparison mode, set the GL_TEXTURE_COMPARE_MODE texture parameter to GL_COMPARE_REF_TO_TEXTURE. The comparison function to use when comparing the reference to the texture is set with the GL_TEXTURE_COMPARE_FUNC texture parameter. Acceptable values are GL_NEVER (always fails), GL_ALWAYS (always succeeds), GL_LESS, GL_LEQUAL, GL_EQUAL, GL_NOT_EQUAL, GL_GEQUAL, and GL_GREATER. The comparison works as follows:

 ref OPERATOR texture

Where ref is the reference value given to the texture lookup function by GLSL, and texture is the value fetched from the texture. So GL_LESS will be true if the reference value is strictly less than the value pulled from the texture.

Edge value sampling[edit]

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.

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:

  • GL_REPEAT: the texture coordinate wraps around the texture. So a texture coordinate of -0.2 becomes the equivalent of 0.8.
  • 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.
  • GL_MIRROR_CLAMP_TO_EDGE (requires OpenGL 4.4 or ARB_texture_mirror_clamp_to_edge): the texture coordinates are clamped to the [-1, 1] range, but the negative coordinates are mirrors of the positive. This effectively makes the texture twice as big through mirroring, but clamps to the edge beyond that.

This also applies to Rectangle Textures, except that the range at which they apply edge sampling is based on the texel width/height of the texture, not the normalized [0, 1] range. Sampling modes are irrelevant for Buffer Textures, as they must use the texelFetch sampling functions and thus cannot sample outside of the texel range of the texture.

Border color[edit]

The GL_CLAMP_TO_BORDER requires a color that edge texels are blended when texture coordinates fall outside of the valid area of the texture. When this this edge mode is used, a border color must be set by setting the GL_TEXTURE_BORDER_COLOR parameter.

The border color can be provided in floating-point values, Normalized Integers, or non-normalized integers, using the various forms of glSamplerParameter/glTexParameter. Note that the border color is a 4-component color, so you must use the v version of the function, and you must provide all four components in a single call.

When using the fv function, the color will be stored as a float. When using iv, the color will be converted to a float via signed normalization. Since the components are GLint 32-bit integers, the range is from [-231, 231). When using the Ii or Iui forms, the color will be stored as signed or unsigned integers, as appropriate.

The border color provided must use integer/float values consistent with the Image Format for the texture being used. For floating-point color formats (including normalized integers), the provided data must be floating point/normalized. For integers, the provided border colors must be signed/unsigned, to match the internal format.

For textures that have depth, the border color must be float/normalized (and only the Red component matters). For stencil-aspect texture fetching, the border color must be unsigned integer (and again, only the Red component matters).

If these formatting rules are violated, undefined behavior occurs.

Seamless cubemap fetching[edit]

Seamless Cubemap per Texture
ARB extension ARB_seamless_cubemap_per_texture
Vendor extension AMD_seamless_cubemap_per_texture

As an OpenGL extension, seamless cubemap filtering can be manipulated on a per-texture or per-sampler object basis. Note that if you use the global version, it will still globally force seamless behavior on all cubemaps.

This is governed by a simple boolean sampler parameter, GL_TEXTURE_CUBE_MAP_SEAMLESS. Setting it to 0 turns it off for that texture/sampler; setting it to any other value causes accesses to the cubemap to be seamless.