Поиск…


Основы текстурирования

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

В OpenGL текстуры могут использоваться для многих вещей, но чаще всего это сопоставление изображения с полигоном (например, треугольником). Чтобы сопоставить текстуру с треугольником (или другим полигоном), мы должны сообщить каждой вершине, какой части текстуры она соответствует. Мы назначаем координату текстуры каждой вершине многоугольника и затем будем интерполировать между всеми фрагментами в этом многоугольнике. Координаты текстуры обычно варьируются от 0 до 1 по оси x и y, как показано на рисунке ниже:

координаты текстуры

Координаты текстуры этого треугольника будут выглядеть так:

GLfloat texCoords[] = {
    0.0f, 0.0f,  // Lower-left corner  
    1.0f, 0.0f,  // Lower-right corner
    0.5f, 1.0f   // Top-center corner
};

Поместите эти координаты в VBO (объект буфера вершин) и создайте новый атрибут для шейдера. У вас должно быть хотя бы один атрибут для вершинных позиций, чтобы создать другое для координат текстуры.


Создание текстуры

Первое, что нужно сделать, - создать объект текстуры, на который будет ссылаться идентификатор, который будет сохранен в неподписанной структуре int:

GLuint texture;
glGenTextures(1, &texture); 

После этого он должен быть привязан, поэтому все последующие команды текстуры будут настраивать эту текстуру:

glBindTexture(GL_TEXTURE_2D, texture); 

Загрузка изображения

Чтобы загрузить изображение, вы можете создать свой собственный загрузчик изображений, или вы можете использовать библиотеку загрузки изображений, такую ​​как SOIL (простая библиотека изображений OpenGL) в c ++ или PNGDecoder TWL в java.

Пример загрузки изображения с помощью SOIL:

int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB); 

Теперь вы можете назначить это изображение текстурному объекту:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

После этого вы должны развязать объект текстуры:

glBindTexture(GL_TEXTURE_2D, 0); 

Параметр Wrap для координат текстуры

Как видно выше, нижний левый угол текстуры имеет УФ (st) координаты (0, 0), а верхний правый угол текстуры имеет координаты (1, 1), но координаты текстуры сетки могут быть в любой диапазон. Чтобы справиться с этим, нужно определить, как текстурные координаты обертываются текстурой.

Параметр обертки для текстуры координаты может быть установлен с glTextureParameter использования GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T и GL_TEXTURE_WRAP_R .

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Возможные параметры:

  • GL_CLAMP_TO_EDGE вызывает GL_CLAMP_TO_EDGE текстурных координат к диапазону [1 / 2N, 1 - 1 / 2N] , где N - размер текстуры в направлении.

  • GL_CLAMP_TO_BORDER делает то же самое, что и GL_CLAMP_TO_EDGE , но в случаях, когда зажим, выбранные данные GL_TEXTURE_BORDER_COLOR заменяются цветом, заданным GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT вызывает GL_REPEAT целочисленной части координаты текстуры. Текстура облицована плиткой .

повторить текстуру

  • GL_MIRRORED_REPEAT : если целая часть координаты текстуры GL_MIRRORED_REPEAT , то она игнорируется. В отличие от того, если целочисленная часть координаты текстуры нечетна, то координата текстуры устанавливается в 1 - frac (s) . fract (s) - это дробная часть координаты текстуры. Это заставляет текстуру отражать каждый второй раз.

зеркальная текстура

  • GL_MIRROR_CLAMP_TO_EDGE вызывает повторение координаты текста как для GL_MIRRORED_REPEAT для одного повторения текстуры, после чего координата должна быть зажата, как в GL_CLAMP_TO_EDGE .

Обратите внимание на значение по умолчанию для GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T и GL_TEXTURE_WRAP_R - GL_REPEAT .


Применение текстур

Последнее, что нужно сделать, это привязать текстуру до вызова рисования:

glBindTexture(GL_TEXTURE_2D, texture);

Текстура и фреймбуфер

Вы можете прикрепить изображение в текстуре к фреймбуферу, чтобы вы могли визуализировать непосредственно эту текстуру.

glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
                       GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D,
                       texture,
                       0);

Примечание. Вы не можете читать и писать из одной и той же текстуры в той же задаче рендеринга, потому что она вызывает неопределенное поведение. Но вы можете использовать: glTextureBarrier() между вызовами рендеринга для этого.

Чтение данных текстуры

Вы можете читать данные текстуры с помощью функции glGetTexImage :

char *outBuffer = malloc(buf_size);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              outBuffer);

Примечание: тип и формат текстур - это только, например, и могут быть разными.

Использование PBO

Если вы привязываете буфер к GL_PIXEL_UNPACK_BUFFER тогда параметр data в glTexImage2D является смещением в этом буфере.

Это означает, что glTexImage2D не нужно ждать, пока все данные будут скопированы из памяти приложения, прежде чем он сможет вернуться, уменьшив накладные расходы в основном потоке.

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*3, NULL, GL_STREAM_DRAW);
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);

//write data into the mapped buffer, possibly in another thread.
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
memcpy(mappedBuffer, image, width*height*3);
SOIL_free_image(image);

// after reading is complete back on the main thread
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);

Но там, где действительно светится PBO, вам нужно прочитать результат рендеринга обратно в память приложения. Чтобы считывать данные пикселов в буфер, привяжите его к GL_PIXEL_PACK_BUFFER тогда параметр данных glGetTexImage будет смещением в этот буфер:

glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, NULL, GL_STREAM_COPY);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);

glGetTexImage(GL_TEXTURE_2D,
              0,
              GL_RGBA,
              GL_UNSIGNED_BYTE,
              null);
//ensure we don't try and read data before the transfer is complete
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);

// then regularly check for completion
GLint result;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(result), NULL, &result);
if(result == GL_SIGNALED){
    glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
    void* mappedBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);

    //now mapped buffer contains the pixel data

    glUnmapBuffer(GL_PIXEL_PACK_BUFFER);

}

Использование текстур в шейдерах GLSL

Вершинный шейдер принимает только координаты текстуры как атрибут вершины и пересылает координаты в шейдер фрагмента. По умолчанию он также гарантирует, что фрагмент получит правильно интерполированную координату на основе ее положения в треугольнике:

layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoordIn;

out vec2 texCoordOut;

void main()
{
    gl_Position = vec4(position, 1.0f);
    texCoordOut = texCoordIn;
}

Затем шейдер фрагмента принимает выходную переменную texCoord в качестве входной переменной. Затем вы можете добавить текстуру в шейдер фрагмента, объявив uniform sampler2D . Чтобы пробовать фрагмент текстуры, мы используем встроенную texture функции, которая имеет два параметра. Сначала это текстура, которую мы хотим отбирать, а вторая - координата этой текстуры:

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

void main()
{
    color = texture(image, texCoordOut);
}

Обратите внимание: image не является прямым идентификатором текстуры. Это идентификатор единицы текстуры, который будет отбираться. В свою очередь, текстуры напрямую не связаны с программами; они привязаны к текстурным единицам. Это достигается за счет того, что сначала блок текстуры активен с glActiveTexture , а затем вызов glBindTexture повлияет на конкретную текстуру. Однако, поскольку блок текстуры по умолчанию является блоком текстур 0 , программы, использующие одну текстуру, могут быть упрощены, если не считать этого вызова.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow