c++ - programas - opengl tutorial for beginners
Subtextura de OpenGL (2)
Tengo datos de imagen y quiero obtener una imagen secundaria de eso para usar como una textura 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);
¿Cómo puedo obtener una imagen secundaria de esa imagen cargada como una textura? Creo que tiene algo que ver con el uso de glTexSubImage2D, pero no tengo ni idea de cómo usarlo para crear una nueva textura que pueda cargar. Vocación:
glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, xWidth, yHeight, GL_RGBA, GL_UNSIGNED_BYTE, m_data);
No hago nada que pueda ver, y llamar a glCopyTexSubImage2D solo forma parte de mi framebuffer. Gracias
Editar: use glPixelStorei. Lo usa para configurar GL_UNPACK_ROW_LENGTH
al ancho (en píxeles) de toda la imagen. Luego llama a glTexImage2D (o lo que sea), pasándole un puntero al primer píxel de la subimagen y al ancho y alto de la subimagen.
No se olvide de restaurar GL_UNPACK_ROW_LENGTH
a 0 cuando haya terminado con él.
Es decir:
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 );
O, si eres alérgico a las matemáticas de puntero:
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: para completar, debo señalar que si está usando OpenGL-ES, entonces no obtiene GL_UNPACK_ROW_LENGTH
. En ese caso, podría (a) extraer la subimagen en un nuevo búfer, o (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 );
}
Para aquellos que se quedaron con OpenGL ES 1.1 / 2.0 en 2018 y posterior, realicé algunas pruebas con diferentes métodos sobre cómo actualizar parte de la textura de los datos de imagen (la imagen es del mismo tamaño que la textura).
Método 1: Copie toda la imagen con glTexImage2D :
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mWidth, mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_Pixels );
Método 2: copie toda la imagen con glTexSubImage2D :
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, m_Pixels );
Método 3: copie la parte de la imagen, línea por línea en un bucle:
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 );
}
Método 4: Copie todo el ancho de la imagen, pero copie verticalmente solo la parte que ha cambiado:
auto *ptr = m_Pixels + (y * mWidth) * 4;
glTexSubImage2D( GL_TEXTURE_2D, 0, 0, y, mWidth, h, GL_RGBA, GL_UNSIGNED_BYTE, ptr );
Y aquí están los resultados de la prueba hecha en PC, 100000 veces actualizando diferentes partes de la textura que fueron aproximadamente 1/5 del tamaño de la textura completa.
- Método 1: 38.17 segundos
- Método 2: 26.09 segundos
- Método 3: 54.83 seg. Más lento
- Método 4: 5,93 segundos: ganador
No sorprende que el método 4 sea el más rápido, ya que copia solo parte de la imagen, y lo hace con una sola llamada a la función glTex ... ().