c++ - Carga de imagen OpenCV para OpenGL Texture
textures (2)
Quiero cargar una imagen (jpg y png) con OpenCV como OpenGL Texture.
Así es como cargo la imagen a OpenGL:
glEnable(GL_TEXTURE_2D);
textureData = loadTextureData("textures/trashbin.png");
cv::Mat image = cv::imread("textures/trashbin.png");
if(image.empty()){
std::cout << "image empty" << std::endl;
}else{
glGenTextures( 1, &textureTrash );
glBindTexture( GL_TEXTURE_2D, textureTrash );
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexImage2D(GL_TEXTURE_2D,0,3,image.cols, image.rows,0,GL_RGB,GL_UNSIGNED_BYTE, image.data);
}
La imagen está cargada, ya que "image.empty" siempre devuelve falso
Aquí es cómo renderizo la escena usando la textura creada:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureTrash);
glm_ModelViewMatrix.top() = glm::translate(glm_ModelViewMatrix.top(),0.0f,-13.0f,-10.0f);
glUniformMatrix4fv(uniformLocations["modelview"], 1, false, glm::value_ptr(glm_ModelViewMatrix.top()));
std::cout << "textureShaderID: " << glGetUniformLocation(shaderProgram,"texture") << std::endl;
glUniform1i(glGetUniformLocation(shaderProgram,"texture"), 0);
objLoader->getMeshObj("trashbin")->render();
Y finalmente el fragmento Shader donde quiero aplicar la textura a mi geometría
#version 330
in vec2 tCoord;
// texture //
// TODO: set up a texture uniform //
uniform sampler2D texture;
// this defines the fragment output //
out vec4 color;
void main() {
// TODO: get the texel value from your texture at the position of the passed texture coordinate //
color = texture2D(texture, tCoord);
}
Las coordenadas de textura provienen de un Objeto de búfer de vértice y están configuradas correctamente desde el archivo .obj. También puedo ver el Objeto en mi escena cuando configuro el color, por ejemplo, rojo en el sombreador de fragmentos, o en vec4 (tCoord, 0,1); entonces el objeto está sombreado en diferentes colores.
Lamentablemente, la pantalla se queda negra cuando quiero aplicar la textura ... ¿Puede alguien ayudarme y decirme por qué se queda negro?
Bien, aquí está mi solución de trabajo, basada en las ideas de "Christan Rau". ¡Gracias por eso!
cv::Mat image = cv::imread("textures/trashbin.png");
//cv::Mat flipped;
//cv::flip(image, flipped, 0);
//image = flipped;
if(image.empty()){
std::cout << "image empty" << std::endl;
}else{
cv::flip(image, image, 0);
glGenTextures(1, &textureTrash);
glBindTexture(GL_TEXTURE_2D, textureTrash);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set texture clamping method
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, // Type of texture
0, // Pyramid level (for mip-mapping) - 0 is the top level
GL_RGB, // Internal colour format to convert to
image.cols, // Image width i.e. 640 for Kinect in standard mode
image.rows, // Image height i.e. 480 for Kinect in standard mode
0, // Border width in pixels (can either be 1 or 0)
GL_BGR, // Input image format (i.e. GL_RGB, GL_RGBA, GL_BGR etc.)
GL_UNSIGNED_BYTE, // Image data type
image.ptr()); // The actual image data itself
glGenerateMipmap(GL_TEXTURE_2D);
}
Al solo mirar el código de carga de texturas, se ignoran muchas consideraciones sobre cómo OpenCV establece las imágenes en la memoria. Ya he explicado que en la dirección opuesta ( glGetTexImage
into OpenCV image) en esta respuesta , pero recapitularé aquí para la dirección CV-GL:
En primer lugar, OpenCV no necesariamente almacena las filas de imágenes apretadas pero puede alinearlas con ciertos límites de bytes (¿no sabe cuánto, al menos 4, pero quizás 8 o más?). Si tiene suerte, utilizará la alineación de 4 bytes y el GL está configurado en el modo de almacenamiento de píxeles predeterminado de alineación de 4 bytes, también. Pero lo mejor es manipular manualmente los modos de almacenamiento de píxeles para estar seguro:
//use fast 4-byte alignment (default anyway) if possible
glPixelStorei(GL_UNPACK_ALIGNMENT, (image.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn''t need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH, image.step/image.elemSize());
Luego debe tener en cuenta el hecho de que OpenCV almacena imágenes de arriba a abajo, mientras que GL utiliza de abajo hacia arriba. Esto podría resolverse simplemente duplicando la coordenada de textura t de forma adecuada (tal vez directamente en el sombreador), pero también podría simplemente voltear la imagen antes de cargarla:
cv::flip(image, flipped, 0);
image = flipped; //maybe just cv::flip(image, image, 0)?
Por último, pero no por ello menos importante, OpenCV almacena imágenes en color en formato BGR, por lo que cargarlas como RGB podría distorsionar los colores. Entonces, use GL_BGR
(requiere OpenGL 1.2, pero ¿quién no tiene eso?) En glTexImage2D
.
Puede que estas no sean la solución completa a su problema (ya que creo que esos errores deberían dar como resultado una imagen distorsionada en lugar de una imagen negra), pero definitivamente son problemas de los que deben ocuparse.
EDITAR: ¿Su sombreador de fragmentos realmente se compila exitosamente (en la versión completa usando la textura)? Te pregunto porque en GLSL 3.30 estás usando la palabra texture
también es el nombre de una función incorporada (que en realidad debería usarse en lugar de la obsoleta función texture2D
), así que tal vez el compilador tenga algunos problemas de resolución de nombres (y tal vez este error se ignora en los sombreadores simplificados, dado que todo el uniforme se optimizará y se sabe que muchos compiladores GLSL son algo más que el estándar estrictamente compatible). Así que intente darle a ese sampler uniform un nombre diferente.