This will sample the texture at the mip level {{param|lod}}. 0 means the [[Textures#Mipmap_range|base level (as set by the appropriate texture parameter)]]. Sampler types that forbid mipmaps (rectangle, buffer, etc), multisample samplers, and shadow cubemap array samplers cannot be used with texture LOD functions.

+

This will sample the texture at the mipmap LOD {{param|lod}}. 0 means the [[Textures#Mipmap_range|base level (as set by the appropriate texture parameter)]]. Sampler types that forbid mipmaps (rectangle, buffer, etc), multisample samplers, and shadow cubemap array samplers cannot be used with texture LOD functions.

−

Note that gradients when using Lod functions (see {{code|textureGrad}} below) are effectively zero. So anisotropic filtering is useless when using this function.

+

[[Sampler_Object#Filtering|Mipmap filtering]] can still be used by selecting fractional levels. A level of 0.5 would be 50% of mipmap 0 and 50% of mipmap 1.

+

+

Note that gradients when using Lod functions (see {{code|textureGrad}} below) are effectively zero. So [[Sampler_Object#Anisotropic_filtering|anisotropic filtering]] is useless when using this function.

=== Projective texture access ===

=== Projective texture access ===

Revision as of 17:28, 6 February 2013

A sampler is a set of GLSL variable types. Variables of one of the sampler types must be uniforms or as function parameters. Each sampler in a program represents a single texture of a particular texture type. The type of the sampler corresponds to the type of the texture that can be used by that sampler.

Sampler types

There are a number of sampler types. The various sampler types are separated into 3 categories, based on the basic data type of the Image Format of the texture that they sample from. These are floating-point, signed integer, and unsigned integer. Floating-point also covers normalized integer formats.

The name of the sampler type in GLSL reflects this grouping. The names are very similar to the names of the vector types in GLSL. Floating-point vectors do not have a prefix; they are just "vec​". Signed integer vectors are "ivec​", and unsigned integer vectors are "uvec​".

So for samplers, floating-point samplers begin with "sampler​". Signed integer samplers begin with "isampler​", and unsigned integer samplers begin with "usampler​". If you attempt to read from a sampler where the texture's Image Format doesn't match the sampler's basic format (usampler2D with a GL_R8I, or sampler1D with GL_R8UI, for example), all reads will produce undefined values.

For the sake of clarity, when you see a g preceding "sampler" in a sampler name, it represents any of the 3 possible prefixes (nothing for float, i for signed integer, and u for unsigned integer).

The rest of the sampler's name refers to the texture type that it is a sampler of. The names map as follows:

Shadow samplers

If a texture is a depth texture and has the depth comparison activated, it cannot be used with a normal sampler. Attempting to do so is an error. Such textures must be used with a shadow sampler. This type changes the texture lookup functions (see below) to increase the vector size of the texture coordinate by one. This extra value is used to compare against the value sampled from the texture.

Because cubemap arrays take 4D texture coordinates, the texture lookup functions take an additional parameter, instead of expanding the vector texture coordinate size.

The result of accessing a shadow texture is always a single float value. This value is on the range [0, 1], which is proportional to the number of samples in the shadow texture that pass the comparison. Therefore, if the resulting value is 0.25, then only 1 out of every 4 values in the shadow comparison passed.

Notice that none of these types have the g prefix. This is because shadow samplers can only be used with textures with depth components. And those are all floating-point (or normalized integer) image formats. Furthermore, the result of the comparison is always a single float.

sampler1DShadow: GL_TEXTURE_1D

sampler2DShadow: GL_TEXTURE_2D

samplerCubeShadow: GL_TEXTURE_CUBE_MAP

sampler2DRectShadow: GL_TEXTURE_RECTANGLE

sampler1DArrayShadow: GL_TEXTURE_1D_ARRAY

sampler2DArrayShadow: GL_TEXTURE_2D_ARRAY

samplerCubeArrayShadow: GL_TEXTURE_CUBE_MAP_ARRAY

Language Definition

A variable of sampler can only be defined in one of two ways. It can be defined as a function parameter or as a uniform variable.

uniformsampler2Dtexture1;voidFunction(insampler2DmyTexture);

Samplers do not have a value. They can not be set by expressions and, with one exception, they cannot be a part of any expression. While they can be function parameters, you can only use them with parameters defined as "in".

Texture lookup functions

The only place where you can use a sampler is in one of the GLSL standard library's texture lookup functions. These functions access the texture referred to by the sampler. They take a texture coordinate as parameters.

There are several kinds of texture functions. Some texture functions do not take certain kinds of samplers. Some of them are not available on all shader stages.

The use of g has the same meaning as previously. Types in bold face represent a range of types, as explained in the description beneath the function.

Texture coordinates

Texture coordinates may be normalized or in texel space. A normalized texture coordinate means that the size of the texture maps to the coordinates on the range [0, 1] in each dimension. This allows the texture coordinate to be independent of any particular texture's size. A texel-space texture coordinate means that the coordinates are on the range [0, size], where size​ is the size of the texture in that dimension.

Rectangle Textures always take texture coordinates in texel space. Unless otherwise noted, all other texture coordinates will be normalized.

Components of a texture coordinate that reference an array layer are not normalized to the number of layers. They specify a layer by index.

Texture size retrieval

The size of a texture can be retrieved by calling this function:

ivec textureSize(gsamplersampler​, int lod​);

This function retrieves the size of the given LOD of the texture bound to sampler​. The sampler can be of any type. For sampler types that refer to textures without mipmaps (eg: samplerRect), no lod​ value is needed.

The dimensionality of the return value, ivec, depends on the type of sampler​. For images that are 1-dimensional, the function returns an int. For 2D images, the function returns ivec2, and for 3D ivec3. The array types return one extra coordinate (eg: 1D arrays return ivec2), with the last coordinate being the number of images in the array of images.

Basic texture access

To sample the texture with normalized texture coordinates, this function is used:

gvec texture(gsamplersampler​, vectexCoord​[, float bias​]);

This samples the texture given by sampler​, at the location texCoord​, with an optional LOD bias value of bias​. For sampler types that cannot have LODs, the bias​ parameter cannot be used.

Sampling from shadow samplers return a "float", representing the result of the comparison. Sampling from other kinds of samplers returns a gvec4, matching the type of gsampler. This function does not work with multisample or buffer samplers.

The size of the vec type of texCoord​ depends on the dimensionality of sampler​. A 1D sampler takes a "float", 2D samplers take "vec2", etc. Array samplers add one additional coordinate for the array level to sample. Shadow samplers add one additional coordinate for the sampler comparison value. Array and shadow samplers add two coordinates: the array level followed by the comparison value. So vec when used with a sampler1DArrayShadow is a "vec3".

Offset texture access

You can add a texel offset to texture coordinates sampled with texture functions. This is useful for sampling from a collection of images all on one texture. This is done with this function:

The texCoord​ will have its value offset by offset​ texels before performing the lookup. Cubemap, multisample, and buffer samplers are not allowed as types for gsampler.

The type ivec has the same type, but in integers, as vec. So when accessing a 2D sampler, vec is "vec2" and ivec is "ivec2". When accessing a 1D sampler, vec is "float" and ivec is "int".

The value of offset​ must be a constant expression. That is, it must be a compile-time constant.

There are minimum and maximum values for the coordinates of offset​. These are queried through GL_MIN_PROGRAM_TEXEL_OFFSET and GL_MAX_PROGRAM_TEXEL_OFFSET.

Lod texture access

If you want to compute the mipmap LOD parameter entirely on your own (instead of biasing the pre-computed LOD), you may use this function:

gvec textureLod(gsamplersampler​, vectexCoord​, float lod​);

This will sample the texture at the mipmap LOD lod​. 0 means the base level (as set by the appropriate texture parameter). Sampler types that forbid mipmaps (rectangle, buffer, etc), multisample samplers, and shadow cubemap array samplers cannot be used with texture LOD functions.

Mipmap filtering can still be used by selecting fractional levels. A level of 0.5 would be 50% of mipmap 0 and 50% of mipmap 1.

Note that gradients when using Lod functions (see textureGrad​ below) are effectively zero. So anisotropic filtering is useless when using this function.

Projective texture access

Projecting a texture onto a surface is often a useful technique. To perform this kind of texture access, this function is available:

gvec textureProj(gsamplersampler​, vecprojTexCoord​[, float bias​]);

The difference between this function and texture​ is that vec is one component larger than it would be for texture​. The previous components are divided by the last components, and this value is used to access the texture.

Array, cubemap, multisample, and buffer samplers cannot be used with this function.

An important note on shadow samplers. The comparison value is still part of the texture coordinate, stored in the next to last component. Because it is part of the texture coordinate, it is also divided by the last coordinate before the comparison. This means that you must pre-multiply the actual value by the projection value.

Gradient texture access

Being able to bias the mipmap LOD or specify the specific mipmap to use is useful, but it is also useful to change the mipmap lod computation in more subtle ways. This function allows you to specify the two gradients for how the texture coordinates change locally:

The type of gradvec​ is a float-vector with a number of components equal to the dimensionality of the sampler type. A 1D sampler uses a "float", etc. Note that shadow sampler types do not add an additional coordinate to gradvec​, so a sampler2DShadow is still "vec2".

This function works for sampler types that are not multisample, buffer texture, or cubemap array samplers, including those that do not have mipmaps (like sampler2DRect).

The values of dTdx​ and dTdy​ are vectors that represent the change of each texture coordinate per pixel of the window's X and Y coordinates.

Mixed texture accesses

There are texture functions for different combination of the above. These are:

textureProjOffset​

textureProjLod​

textureProjLodOffset​

textureProjGrad​

textureProjGradOffset​

textureLodOffset​

textureGradOffset​

The variations that add parameters to the functions, everything except "Proj", add them in the order that the names appear in the function. So textureProjLodOffset​ has this signature:

The accepted sampler types is the intersection of all sampler types that each function accepts. "Proj" cannot take cubemaps and "Lod" cannot take rectangles, so textureProjLod​ cannot take either type.

Direct texel fetches

The above texture functions all use filtering and normalized texture coordinates (except when using rectangle samplers). It is occassionally useful to forgo this and directly access a texel value with non-normalized coordinates. This is done through one of these functions:

The texCoord​ parameter is an unnormalized texture coordinate. The lod​ specifies which mipmap to sample from; if the sampler type does not have mipmaps, this parameter will not be present. The offset version applies an integer texel offset to the texture coordinate before doing the texture access. As before, the offset​ must be a constant expression. The sample​ specifies the sample number to fetch from for multisample sampler types.

texelFetch​ is the only texturing function (besides textureSize​) that takes multisample and buffer samplers. When using multisample samplers, the user must pass a sample​ parameter. This tells the system which sample to retrieve.

Texture lookup in shader stages

Texture accessing is not limited to just Fragment Shaders, though this is the primary place where textures are accessed. Any GLSL shader stage may access textures. However, there are certain caveats to using some functions.

Mipmapping works based off of the angle of the rendered primitive relative to the window. This makes sense in the context of a fragment shader. But in any other shader stage, there is no rendered primitive yet; there may be a vertex or a primitive, but the space of the primitive is unknown.

Because of this, the texture functions have slightly different behavior in non-fragment shader stages. The "Lod" and "Grad" functions all work as expected, as does the texelFetch​ functions. The result of using any other texturing functions for mipmapped textures outside of a fragment shader is undefined.

Non-uniform flow control

In fragment shaders, there is one other circumstance that can cause all of your non-"Lod" or "Grad" texture accesses to become undefined: non-uniform flow control.

Uniform flow control for a particular location in code means that, no matter how a shader is executed, the shader will follow the same path to get to that location of code. Consider the following GLSL code for a fragment shader:

The first texture access happens in uniform flow control. Thus, the texture access produces definite results. However, both of the other two texture accesses are not in uniform flow. If the textures they are accessing use mipmapping or anisotropic filtering of any kind, then any texture function that is not "Lod" or "Grad" will retrieve undefined results.

Note: The GLSL compiler will not give you an error for this. It is perfectly legal GLSL code. It only becomes undefined when certain texture state is set on those textures. Specifically, if mipmap or anisotropic filtering is used.

There are two ways to solve this. The simplest is to restructure the code to always do the second texture access, but only add it based on the condition:

The other alternative, which must be used in cases that are not so simple to resolve, is to get gradients for each pair of texture coordinates the texture coordinates with the dFdx​ and dFdy​ functions. Then use those gradients when fetching the textures.

It is important to get the gradients before going into non-uniform flow code. The dFdx​ and dFdy​ become just as useless as the texture​ calls within non-uniform flow control code.

Binding textures to samplers

Uniforms of sampler types are used in GLSL to represent a texture of a particular kind. Therefore, sampler types represent textures. The way a program is associated with textures is somewhat unintuitive. The mapping is done with the rendering context.

The OpenGL rendering context has multiple independent bind locations for textures called texture image unit. The function to switch which bind location is current is glActiveTexture​. The bind locations are named in this function GL_TEXTURE0, GL_TEXTURE1, etc. Alternatively, you can use bind locations of the form GL_TEXTURE0 + i, where i is a texture unit number between 0 and the implementation-defined constant GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

This means you can bind 4 textures to texture units 0, 1, 3, and 8, so long as GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS for the implementation is greater than 8.

You can also bind Sampler Objects (no direct relation to samplers in GLSL) to a texture image unit. This makes it much easier to centralize sampling parameters, or to use the same texture with different sampling parameters.

The value of a sampler uniform in a program is not a texture object, but a texture image unit index. So you set the texture unit index for each sampler in a program. Then you bind the textures and sampler objects you wish to use to those texture units. Bind the program to the context, and rendering with that program will use those textures. To set the value of a sampler, use glUniform1i​ or glUniform1iv​ for an array of samplers.

Here is an example of how to do this.

//Initial program setup.glLinkProgram(program);//Initial linkGLintbaseImageLoc=glGetUniformLocation(program,"baseImage");GLintnormalMapLoc=glGetUniformLocation(program,"normalMap");GLintshadowMapLoc=glGetUniformLocation(program,"shadowMap");glUseProgram(program);glUniform1i(baseImageLoc,0);//Texture unit 0 is for base images.glUniform1i(normalMapLoc,2);//Texture unit 2 is for normal maps.glUniform1i(shadowMapLoc,4);//Texture unit 4 is for shadow maps.//When rendering an objectwith this program.glActiveTexture(GL_TEXTURE0+0);glBindTexture(GL_TEXTURE_2D,object1BaseImage);glBindSampler(0,linearFiltering);glActiveTexture(GL_TEXTURE0+2);glBindTexture(GL_TEXTURE_2D,object1NormalMap);glBindSampler(2,linearFiltering);//Same filtering as beforeglActiveTexture(GL_TEXTURE0+4);glBindTexture(GL_TEXTURE_2D,shadowMap);glBindSampler(4,depthComparison);//Special sampler for depth comparisons.//Render stuffglDraw*();//Render another object with some different textures.glActiveTexture(GL_TEXTURE0+0);glBindTexture(GL_TEXTURE_2D,object2BaseImage);//Use the same sampler as before.glActiveTexture(GL_TEXTURE0+2);glBindTexture(GL_TEXTURE_2D,object2NormalMap);//Use the same sampler as before.//Use the same shadow map, so no need to unbind/bind.//Render stuffglDraw*();

Notice that the shadow map does not need to be changed here. This helps minimize the number of state changes. Your program could even have a global convention that texture image unit 4 is always used for shadow maps. Since all objects used the same shadow map, you can bind the shadow map before you start rendering anything, and you only have to bind it once per frame.

If a program doesn't use certain texture image units, it is still fine to have a texture bound to them. They will not affect the rendering in any way.

Verison 4.20 binding

Shaders that support GLSL 4.20 or the extension ARB_shading_language_420pack can assign the default binding of samplers within a shader. For example:

#version 420//#extension GL_ARB_shading_language_420pack: enable Use for GLSL versions before 420.layout(binding=0)uniformsampler2DdiffuseTex;

This causes the initial value for the diffuseTex​ uniform to be the sampler 0. You may call glUniform​ to change the binding later. The binding​ must be a compile-time constant.