Расширение ARB_sampler_objects

Если посмотреть на текстуры в OpenGL, то видно, что они состоят из самого изображения (включая пирамиду mipmap-уровней, грани кубической карты и т.п.) и параметров, управляющих доступом к этому изображению (т.н. sampler state). К этим параметрам относятся режим фильтрации текстуры, режим отсечения текстурных координат, работа с mipmap-уровнями и т.п. При этом сами данные параметры не связаны непосредственно с изображением - они только управляют доступом к нему.

Такое объединение двух различных сущностей (image data и sampler state) в один текстурный объект оказывается довольно неудобным - изменение параметров доступа не самая дешевая операция, периодически возникает необходимость обращаться к одной и той же текстуре с разными параметрами выборки. Часто встречается и обратное - большое число различных текстур используются с одними и теми же параметрами выборки и все эти параметры нужно задавать отдельно для каждой из этих текстур.

Расширение ARB_sampler_objects, входящее в OpenGL 3.3, позволяет отделить параметры выборки от самой текстуры. Для этого вводится новый тип объекта в OpenGL - сэмплер (sampler object). Сэмплер фактически является контейнером для параметров выборки из текстур. Для каждого сэмплера можно задавать параметров выборки (а не привязывать их как ранее к самой текстуре).

Рис 1. Сэмплер, как контейнер для параметров выборки.

Любой сэмплер может быть "привязан" к любому текстурному блоку (texture unit), можно "привязать" один и тот же сэмплер сразу к нескольким текстурным блокам. После этого, параметры для выборки из текстуры будут браться из сэмплера, "привязанного" к текстурному блоку, связанному с текстурой (параметры выборки, заданные для самой текстуры, в этом случае полностью игнорируются).

Таким образом можно легко создать один объект-сэмплер, задать для него все необходимые параметры выборки и привязать ко всем используемым текстурным блоками. Тогда именно этот объект будет управлять параметрами выборки из всех текстур и если нужно будет изменить какой-либо параметр, то это достаточно будет сделать всего один раз - для сэмплера.

Рис 2. Один сэмплер управляет выборками сразу из нескольких текстурных блоков.

С другой стороны можно использовать несколько разных сэмплеров для доступа к одной и той же текстуре - при этом в каждом текстурном блоке выбирается данная текстура и соответствующий сэмплер. Тем самым сэмплер является удобным механизмом управления параметрами выборки из различных текстур.

Рис 3. Доступ к одной и той же текстуре через несколько текстурных блоков, в каждом блоке - свой сэмплер.

Подобно многим другим объектам OpenGL каждый сэмплер идентифицируется беззнаковым целым числом, не равным нулю. Для создания и уничтожения сэмплеров служат функции glGenSamplers и glDeleteSamplers:

void glGenSamplers    ( GLsizei count, GLuint * samplers );
void glDeleteSamplers ( GLsizei count, GLuint * samplers );

Проверить, является ли заданное число идентификатором какого-либо сэмплера можно при помощи функции glIsSampler:

GLboolean glIsSampler ( GLuint sampler );

При помощи функции glBindSampler можно "привязать" заданный сэмплер sampler к текстурному блоку unit:

void glBindSampler ( GLuint uint, GLuint sampler );

Для того, чтобы "отвязать" сэмплер от текстурного блока, используется та же функция glBindSampler с параметром sampler равным нулю.

Следующие функции служат для задания параметров сэмплера:

void glSamplerParameteri    ( GLuint sampler, GLenum pname, int param );
void glSamplerParameterf    ( GLuint sampler, GLenum pname, float param );
void glSamplerParameteriv   ( GLuint sampler, GLenum pname, const int    * params );
void glSamplerParameterfv   ( GLuint sampler, GLenum pname, const float  * params );
void glSamplerParameterIiv  ( GLuint sampler, GLenum pname, const int    * params );
void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint * params );

Для того, чтобы получить из сэмплера значения какого-либо его параметра, служат следующие функции:

void glGetSamplerParameteriv   ( GLuint sampler, GLenum pname, int    * params );
void glGetSamplerParameterfv   ( GLuint sampler, GLenum pname, float  * params );
void glGetSamplerParameterIiv  ( GLuint sampler, GLenum pname, int    * params );
void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint * params );

Узнать идентификатор сэмплера выбранного в текущем текстурном блоке можно при помощи вызова функции glGetIntegerv GL_SAMPLER_BINDING

glGetIntegerv ( GL_SAMPLER_BINDING, &sampler );

Для удобства работы "завернем" работу с сэмплером в класс на С++. На следующем листинге приводится заголовочный файл Sampler.h.

//
// ARB_sampler_object C++ wrapper
//

#ifndef __SAMPLER_OBJECT__
#define __SAMPLER_OBJECT__

#include    "libExt.h"

class   Sampler
{
    GLuint  id;
    
public:
    Sampler  ()
    {
        glGenSamplers ( 1, &id );
    }
    
    ~Sampler ()
    {
        glDeleteSamplers ( 1, &id );
    }
    
    bool    isOk () const
    {
        return id != 0 && glIsSampler ( id );
    }
    
    GLuint  getId () const
    {
        return id;
    }
    
    void bind ( int unit )
    {
        glBindSampler ( unit, id );
    }
    
    void    unbind ( int unit )
    {
        glBindSampler ( unit, 0 );
    }
    
    void    setWrap ( GLenum sWrap, GLenum tWrap, GLenum rWrap )
    {
        glSamplerParameteri ( id, GL_TEXTURE_WRAP_S, sWrap );
        glSamplerParameteri ( id, GL_TEXTURE_WRAP_T, tWrap );
        glSamplerParameteri ( id, GL_TEXTURE_WRAP_R, rWrap );
    }
    
    void    setMinFilter ( GLenum minFilter )
    {
        glSamplerParameteri ( id, GL_TEXTURE_MIN_FILTER, minFilter );
    }
    
    void    setMagFilter ( GLenum magFilter )
    {
        glSamplerParameteri ( id, GL_TEXTURE_MAG_FILTER, magFilter );
    }
    
    void    setMinLod  ( int minLod )
    {
        glSamplerParameteri ( id, GL_TEXTURE_MIN_LOD, minLod );
    }
    
    void    setMaxLod  ( int maxLod )
    {
        glSamplerParameteri ( id, GL_TEXTURE_MAX_LOD, maxLod );
    }
    
    void    setLodBias ( float bias )
    {
        glSamplerParameterf ( id, GL_TEXTURE_LOD_BIAS, bias );
    }
    
    void    setMaxAnisotropy ( float anisotropy )
    {
        glSamplerParameteri ( id, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy );
    }
    
    void    setTextureCompare ( GLenum mode, GLenum func )
    {
        glSamplerParameteri ( id, GL_TEXTURE_COMPARE_MODE, mode );
        glSamplerParameteri ( id, GL_TEXTURE_COMPARE_FUNC, func );
    }
    
    
    GLenum  getSWrap         () const;
    GLenum  getTWrap         () const;
    GLenum  getRWrap         () const;
    GLenum  getMinFilter     () const;
    GLenum  getMagFilter     () const;
    int     getMinLod        () const;
    int     getMaxLod        () const;
    float   getLodBias       () const;
    
    float   getMaxAnisotropy      () const;
    GLenum  getTextureCompareMode () const;
    GLenum  getTextureCompareFunc () const;

    static GLuint activeSampler ();         // return sampler bound to current texture unit
};
#endif

На следующем листинге приводится соответствующий С++ файл:

//
// ARB_sampler_object C++ wrapper
//

#include    "Sampler.h"

GLenum  Sampler :: getSWrap () const
{
    GLenum sWrap;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_WRAP_S, (GLint *)&sWrap );

    return sWrap;
}

GLenum  Sampler :: getTWrap () const
{
    GLenum tWrap;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_WRAP_T, (GLint *)&tWrap );

    return tWrap;
}

GLenum  Sampler :: getRWrap () const
{
    GLenum rWrap;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_WRAP_R, (GLint *)&rWrap );

    return rWrap;
}

GLenum  Sampler :: getMinFilter () const
{
    GLenum filter;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_MIN_FILTER, (GLint *)&filter );
    
    return filter;
}

GLenum  Sampler :: getMagFilter () const
{
    GLenum filter;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_MAG_FILTER, (GLint *)&filter );
    
    return filter;
}

int     Sampler :: getMinLod  () const
{
    int lod;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_MIN_LOD, &lod );
    
    return lod;
}

int     Sampler :: getMaxLod  () const
{
    int lod;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_MAX_LOD, &lod );
    
    return lod;
}

float   Sampler :: getLodBias () const
{
    float   bias;
    
    glGetSamplerParameterfv ( id, GL_TEXTURE_LOD_BIAS, &bias );
    
    return bias;
}

float   Sampler :: getMaxAnisotropy () const
{
    float   anisotropy;
    
    glGetSamplerParameterfv ( id, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropy );
    
    return anisotropy;
}

GLenum  Sampler :: getTextureCompareMode () const
{
    GLenum  mode;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_COMPARE_MODE, (GLint *)&mode );
    
    return mode;
}

GLenum  Sampler :: getTextureCompareFunc () const
{
    GLenum func;
    
    glGetSamplerParameteriv ( id, GL_TEXTURE_COMPARE_FUNC, (GLint *)&func );
    
    return func;
}

GLuint Sampler :: activeSampler ()
{
    GLuint  sampler;
    
    glGetIntegerv ( GL_SAMPLER_BINDING, (GLint *)&sampler );
    
    return sampler;
}

По этой ссылке можно скачать весь исходный код к этой статье.

Обратите внимание, что для компиляции данного класса необходимы последние версии библиотек libExt и libTexture.