Texture rectangles, NPOT-текстуры

Обычно в OpenGL требуется, чтобы размеры всех используемых текстур были степенями двойки. Это в частности позволяет просто и эффективно реализовывать пирамидальное фильтрование (mipmapping) и доступ к текстурам.

Однако в целом ряде случаев (например, при обработке изображений), мы сталкиваемся с текстурами, размеры которых уже не являются степенями двух (так называемые Non-Power-Of-Two, NPOT-текстуры).

Простейшим подходом к использованию таких текстур является их перемасштабирование, в частности именно это делает функция gluBuild2DMipmaps.

Однако такое перемасштабирование далеко не всегда желательно, да и не всегда возможно (например, если вы хотите применить обработку изображений, получаемых при полноэкранном рендеринге). И именно тогда на помощь приходят два возможных пути.

Самый простой - это использование расширения ARB_texture_non_power_of_two. Если это расширение поддерживается, то можно свободно работать с NPOT-текстурами точно так же, как и с обычными (РОТ) текстурами. При этом NPOT-текстуры будут вести себя полностью аналогично обычным текстурам, т.е. для них будет поддерживаться пирамидальное фильтрование, различные режимы отсечения текстурных координат и т.п.

Таким образом, если расширение ARB_texture_non_power_of_two поддерживается, то можно вообще не думать, являются ли размеры текстуры степенями двойки или нет.

Однако данное расширение поддерживается далеко не всеми графическими ускорителями (так GPU GeForceFX 5xxx его не поддерживает). Кроме того в ряде случаев (обработка изображений, GPGPU) удобнее использовать текстурные координаты не из отрезка [0,1], а из [0,w], где w - ширина (высота) текстуры в текселах.

В этом случае можно воспользоваться одним из расширений NV_texture_rectangle, EXT_texture_rectangle и ARB_texture_rectangle. Далее мы рассмотрим только последнее из них, поскольку они практически одинаковы.

Расширение ARB_texture_rectangle вводит новый тип текстур (texture target) - двухмерную текстуру типа GL_TEXTURE_RECTANGLE_ARB. Для такой текстуры ее размеры (ширина и высота ) не обязаны быть степенями двойки.

Однако работа с такими текстурами несет в себе ряд отличий от работы с обычными текстурами:

1. Для этих текстур не поддерживается пирамидальное фильтрование (mipmapping).

2. В качестве режима отсечения текстурных координат могут использоваться лишь GL_CLAMP, GL_CLAMP_TO_EDGE и GL_CLAMP_TO_BORDER.

3. Для этих текстур не поддерживается "бортик" вокруг текстуры (хотя им все равно никто не пользуется :)).

4. Текстурные координаты для таких текстур изменяются на прямоугольнике [0,w]x[0,h>, где w и h - ширина и высота текстуры в текселах.

Для загрузки таких текстур используются стандартные функции flTexImage2D, glSubTexImage2D, glCopyTexImage2D и glCopySubTexImage2D точно так же, как и для обычных текстур (только в качестве параметра target выступает GL_TEXTURE_RECTANGLE_ARB).

Для разрешения/запрещения использования таких текстур служат следующие вызовы:

glEnable  ( GL_TEXTURE_RECTANGLE_ARB );
glDisable ( GL_TEXTURE_RECTANGLE_ARB );

При этом данный тип текстуры обладает более высоким приоритетом, чем обычные 2D-текстуры, но меньшим, чем 3D-текстуры.

Текстуры данного типа могут использоваться в качестве теневых карт, в этом случае третья текстурная координата r изменяется в привычном диапазоне [0,1].

Данный тип текстур поддерживается и в GLSL. Для описания таких текстур следует использовать один из следующих типов - sampler2DRect или sampler2DRectShadow.

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

vec4 texture2DRect     ( sampler2DRect sampler, vec2 coord );
vec4 texture2DRectProj ( sampler2DRect sampler, vec3 coord );
vec4 texture2DRectProj ( sampler2DRect sampler, vec4 coord );

Для "Proj"-вариантов функций доступа первые две текстурные координаты (s и t) делятся на последнюю текстурную координату (т.е. если текстурные координаты переданы как vec4, то третья текстурная координата будет проигнорирована, а деление будет произведено на четвертую координату).

Ниже приводится фрагментный шейдер реализующий эффект edge-detect для NPOT-текстуры.

uniform sampler2DRect mainTex;

void main (void)
{
    const vec3  luminance  = vec3 ( 0.3, 0.59, 0.11 );
    const vec2  d01        = vec2 ( 0.0, 1.0 );
    const vec2  d10        = vec2 ( 1.0, 0.0 );
    const float scale      = 2.5;
	
    float c1 = dot ( luminance, texture2DRect ( mainTex, gl_TexCoord [0].xy + d01 ).rgb );
    float c2 = dot ( luminance, texture2DRect ( mainTex, gl_TexCoord [0].xy - d01 ).rgb );
    float c3 = dot ( luminance, texture2DRect ( mainTex, gl_TexCoord [0].xy + d10 ).rgb );
    float c4 = dot ( luminance, texture2DRect ( mainTex, gl_TexCoord [0].xy - d10 ).rgb );

    gl_FragColor = vec4 ( vec3 ( scale * ( abs ( c1 - c2 ) + abs ( c2 - c3 ) ) ), 1.0 );
}

Полный исходный текст программы, осуществляющий рендеринг в NPOT-текстуру и применяющий к ней данный эффект можно скачать по этой ссылке.

Также можно скачать уже откомпилированные программы для M$ Windows, Linux и Mac OS X .

Определение является ли данное число степенью двух:

bool isPowerOfTwo ( unsigned v )
{
    return (v & (v - 1)) == 0;
}

Valid HTML 4.01 Transitional

Напиши мне
Используются технологии uCoz