Субтекстурирование openGL

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

glGenTextures(1, &m_name);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldName);
glBindTexture(GL_TEXTURE_2D, m_name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_data);

Как я могу загрузить дополнительное изображение этого изображения в виде текстуры. Я думаю, что это как-то связано с использованием glTexSubImage2D, но я понятия не имею, как использовать его для создания новой текстуры, которую я могу загрузить. Вызов:

glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, xWidth, yHeight, GL_RGBA, GL_UNSIGNED_BYTE, m_data);

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


person DavidG    schedule 15.10.2008    source источник


Ответы (2)


Изменить: использовать glPixelStorei. Вы используете его, чтобы установить GL_UNPACK_ROW_LENGTH в ширину (в пикселях) всего изображения. Затем вы вызываете glTexImage2D (или что-то еще), передавая ему указатель на первый пиксель фрагмента изображения, а также ширину и высоту фрагмента изображения.

Не забудьте восстановить GL_UNPACK_ROW_LENGTH до 0, когда закончите с этим.

Ie:

glPixelStorei( GL_UNPACK_ROW_LENGTH, img_width );
char *subimg = (char*)m_data + (sub_x + sub_y*img_width)*4;
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, sub_width, sub_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, subimg );
glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );

Или, если у вас аллергия на математику указателей:

glPixelStorei( GL_UNPACK_ROW_LENGTH, img_width );
glPixelStorei( GL_UNPACK_SKIP_PIXELS, sub_x );
glPixelStorei( GL_UNPACK_SKIP_ROWS, sub_y );

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, sub_width, sub_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_data );

glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );

Edit2: Для полноты картины я должен указать, что если вы используете OpenGL-ES, вы не получите GL_UNPACK_ROW_LENGTH. В этом случае вы можете либо (а) извлечь часть изображения в новый буфер самостоятельно, либо (б)...

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, sub_width, sub_height, 0, GL_RGBA, GL_UNSIGNED_BYTES, NULL );

for( int y = 0; y < sub_height; y++ )
{
    char *row = m_data + ((y + sub_y)*img_width + sub_x) * 4;
    glTexSubImage2D( GL_TEXTURE_2D, 0, 0, y, sub_width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row );
}
person Community    schedule 15.10.2008
comment
По сути, у меня есть изображение (как необработанные данные), и я хочу использовать часть этого изображения в качестве текстуры. Я знаю, как загрузить все изображение в виде текстуры, но не знаю, как использовать только его часть. - person DavidG; 15.10.2008
comment
Плакат ответил на это. Если у вас есть образ в памяти, он каким-то образом хранится. Если вы использовали glTexImage2D(...GL_RGBA, GL_UNSIGNED_BYTE) для загрузки, то есть байт для значений R, G, B и альфа. Изображения сохраняются с пикселем (0, 0), начинающимся с позиции 0. Пиксель x в строке y начинается с изображения[width*y+x][0] - person mstrobl; 15.10.2008
comment
так как я использую openGL ES, в итоге я сделал первый вариант, который вы указали, то есть извлечение фрагмента изображения в новый буфер. к сожалению, на устройстве это больше не работает, поэтому я собираюсь переработать текстуру, чтобы мне не нужно было решать проблему. - person DavidG; 15.10.2008

Для тех, кто застрял с OpenGL ES 1.1/2.0 в 2018 году и позже, я провел несколько тестов с различными методами обновления части текстуры из данных изображения (изображение имеет тот же размер, что и текстура).

Способ 1. Скопируйте изображение целиком с помощью glTexImage2D:

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_Pixels );

Способ 2. Скопируйте изображение целиком с помощью glTexSubImage2D:

glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, m_Pixels );

Способ 3. Скопируйте часть изображения построчно в цикле:

auto *ptr = m_Pixels + (x + y * mWidth) * 4;
for( int i = 0; i < h; i++, ptr += mWidth * 4 ) {
    glTexSubImage2D( GL_TEXTURE_2D, 0, x, y+i, w, 1, GL_RGBA, GL_UNSIGNED_BYTE, ptr );
}

Метод 4. Скопируйте изображение по всей ширине, но по вертикали скопируйте только измененную часть:

auto *ptr = m_Pixels + (y * mWidth) * 4;
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, y, mWidth, h, GL_RGBA, GL_UNSIGNED_BYTE, ptr );

А вот результаты теста, проведённого на ПК, по 100 000 раз обновившему разные части текстуры, которые составляли примерно 1/5 размера всей текстуры.

  • Способ 1 — 38,17 сек.
  • Способ 2 - 26,09 сек.
  • Метод 3 — 54,83 с — самый медленный
  • Метод 4 – 5,93 сек – победитель

Неудивительно, что метод 4 является самым быстрым, так как он копирует только часть изображения и делает это с помощью одного вызова функции glTex...().

person vedranm    schedule 19.01.2018