Sampler Object

From OpenGL.org
Jump to: navigation, search
Sampler Object
Core in version 4.4
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

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

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

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.

Note: Generally speaking, all GL 3.x+ hardware will do filtering correctly.

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.

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

Note: This is not core functionality; it is governed by the extension GL_EXT_texture_filter_anisotropic. However, this extension is available virtually everywhere.

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.

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.

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.

LOD range

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

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 added to the bias specified in one of the texture accessing functions in GLSL), which is used to select the image. 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

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.

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

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​ (only available with OpenGL 4.4 or ARB_texture_mirror_clamp_to_edge: the texture is clamped to the [-1, 1] range, but mirrors the negative direction with the positive. Basically, it acts as GL_CLAMP_TO_EDGE​, except that it takes the absolute value of the texture coordinates before clamping.

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. This does not apply to Buffer Textures, as they must use the texelFetch​ sampling functions and thus cannot sample outside of the texel range of the texture.

Border color

The GL_CLAMP_TO_BORDER​ defines 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 with GL_BORDER_COLOR​.

The border color can be provided in floating-point values, normalized integers, or non-normalized integers, using the various forms of glSamplerParameter/glTexParameter.

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​, 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 will then be converted to a value appropriate for the Image Format of the texture when it is actually used.

Note that the border color is a 4-component color, so you must use the v version of the function to provide all four components.

Seamless cubemap fetching

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.