10

我有图像数据,我想获取它的子图像以用作 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 只占用了我的帧缓冲区的一部分。谢谢

4

2 回答 2

30

编辑:使用 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. 在这种情况下,您可以 (a) 自己将子图像提取到新缓冲区中,或者 (b)...

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 );
}
于 2008-10-15T17:05:57.613 回答
4

对于那些在 2018 年及以后坚持使用OpenGL ES 1.1/2.0的人,我用不同的方法做了一些测试,如何从图像数据中更新部分纹理(图像与纹理大小相同)。

方法 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 );

这是在 PC 上进行的测试结果,通过 100000 次更新纹理的不同部分,大约是整个纹理大小的 1/5。

  • 方法 1 - 38.17 秒
  • 方法 2 - 26.09 秒
  • 方法 3 - 54.83 秒 - 最慢
  • 方法 4 - 5.93 秒 -获胜者

毫不奇怪,方法 4 最快,因为它只复制图像的一部分,并且只需调用 glTex...() 函数即可。

于 2018-01-19T01:41:36.863 回答