Las texturas de OpenGL aparecen solo en negro

Estoy tratando de aplicar una textura a un quad, pero solo obtengo una caja negra en lugar de la textura. Estoy usando DevIL para cargar imágenes de archivos y OpenGL hace el rest.

Esto es lo que estoy haciendo hasta ahora:

La siguiente clase resume la representación de DevIL para una imagen.

#include "Image.h" Image::Image() { ilGenImages(1, &this->imageId); } Image::~Image() { ilDeleteImages(1, &this->imageId); } ILint Image::getWidth() { return this->width; } ILint Image::getHeight() { return this->height; } ILint Image::getDepth() { return this->depth; } ILint Image::getBpp() { return this->bpp; } ILint Image::getFormat() { return this->format; } ILubyte* Image::getData() { return ilGetData(); } bool Image::loadFromFile(wchar_t *filename) { // Load the image from file. ILboolean retval = ilLoadImage(filename); if (!retval) { ILenum error; while ((error = ilGetError()) != IL_NO_ERROR) { wcout << error << L" " <width = ilGetInteger(IL_IMAGE_WIDTH); this->height = ilGetInteger(IL_IMAGE_HEIGHT); this->depth = ilGetInteger(IL_IMAGE_DEPTH); this->bpp = ilGetInteger(IL_IMAGE_BPP); this->format = ilGetInteger(IL_IMAGE_FORMAT); return true; } bool Image::convert() { ILboolean retval = ilConvertImage(IL_RGBA, IL_UNSIGNED_BYTE); if (!retval) { ILenum error; while ((error = ilGetError()) != IL_NO_ERROR) { wcout << error << L" " << iluErrorString(error); } return false; } return true; } bool Image::scale(ILint width, ILint height, ILint depth) { ILboolean retval = iluScale(width, height, depth); if (!retval) { ILenum error; while ((error = ilGetError()) != IL_NO_ERROR) { wcout << error << L" " <imageId); } 

Esta clase abstrae la representación de textura para OpenGL.

 #include "Texture.h" Texture::Texture(int width, int height) { glGenTextures(1, &this->textureId); this->width = width; this->height = height; } int Texture::getWidth() { return this->width; } int Texture::getHeight() { return this->height; } void Texture::initFilter() { // We will use linear interpolation for magnification filter. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // We will use linear interpolation for minifying filter. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } void Texture::unpack() { glPixelStoref(GL_UNPACK_ALIGNMENT, 1); } void Texture::bind() { glBindTexture(GL_TEXTURE_2D, this->textureId); } Texture::~Texture() { glDeleteTextures(1, &this->textureId); } 

La siguiente clase contiene el proceso de carga de texturas.

 #include "TextureLoader.h" void TextureLoader::initialize() { if (ilGetInteger(IL_VERSION_NUM) bind(); bool retval = image->loadFromFile(filename); if (!retval) { debug("Could not load image from file."); return 0; } retval = image->convert(); if (!retval) { debug("Could not convert image from RGBA to unsigned byte"); } int pWidth = getNextPowerOfTwo(image->getWidth()); int pHeight = getNextPowerOfTwo(image->getHeight()); int size = pWidth * pHeight; retval = image->scale(pWidth, pHeight, image->getDepth()); if (!retval) { debug("Could not scale image from (w: %i, h: %i) to (w: %i, h: %i) with depth %i.", image->getWidth(), image->getHeight(), pWidth, pHeight, image->getDepth()); return 0; } // Generate some space for a texture and bind it. Texture *texture = new Texture(image->getWidth(), image->getHeight()); texture->bind(); // Set the interpolation filters. texture->initFilter(); // Unpack pixels. texture->unpack(); ILubyte *imageData = image->getData(); TextureLoader::setColorKey(imageData, size, new Color(0, 0, 0)); TextureLoader::colorize(imageData, size, new Color(255, 0, 0)); debug("bpp: %i", image->getBpp()); debug("width: %i", image->getWidth()); debug("height: %i", image->getHeight()); debug("format: %i", image->getFormat()); // Map image data to texture data. glTexImage2D(GL_TEXTURE_2D, 0, image->getBpp(), image->getWidth(), image->getHeight(), 0, image->getFormat(), GL_UNSIGNED_BYTE, imageData); delete image; return texture; } void TextureLoader::setColorKey(ILubyte *imageData, int size, Color *color) { for (int i = 0; i r && imageData[i + 1] == color->g && imageData[i + 2] == color->b) { imageData[i + 3] = 0; } } } void TextureLoader::colorize(ILubyte *imageData, int size, Color *color) { for (int i = 0; i r)) >> 8; int rg = (int(imageData[i + 1]) * int(color->g)) >> 8; int rb = (int(imageData[i + 2]) * int(color->b)) >> 8; int fak = int(imageData[i]) * 5 - 4 * 256 - 138; if (fak > 0) { rr += fak; rg += fak; rb += fak; } rr = rr < 255 ? rr : 255; rg = rg < 255 ? rg : 255; rb = rb  0 ? (GLubyte) rr : 1; imageData[i + 1] = rg > 0 ? (GLubyte) rg : 1; imageData[i + 2] = rb > 0 ? (GLubyte) rb : 1; } } 

La última clase hace el dibujo.

 #include "Texturizer.h" void Texturizer::draw(Texture *texture, float x, float y, float angle) { // Enable texturing. glEnable(GL_TEXTURE_2D); // Bind the texture for drawing. texture->bind(); // Enable alpha blending. glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); int width = texture->getWidth(); int height = texture->getHeight(); // Create centered dimension vectors. b2Vec2 vertices[4]; vertices[0] = 0.5f * b2Vec2(- width, - height); vertices[1] = 0.5f * b2Vec2(+ width, - height); vertices[2] = 0.5f * b2Vec2(+ width, + height); vertices[3] = 0.5f * b2Vec2(- width, + height); b2Mat22 matrix = b2Mat22(); matrix.Set(angle); glBegin(GL_QUADS); for (int i = 0; i < 4; i++) { float texCoordX = i == 0 || i == 3 ? 0.0f : 1.0f; float texCoordY = i < 2 ? 0.0f : 1.0f; glTexCoord2f(texCoordX, texCoordY); // Rotate and move vectors. b2Vec2 vector = b2Mul(matrix, vertices[i]) + meter2pixel(b2Vec2(x, y)); glVertex2f(vector.x, vector.y); } glEnd(); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); } 

Por último, pero no menos importante, el siguiente método inicializa OpenGL (y activa la inicialización de DevIL):

 void GraphicsEngine::initialize(int argc, char **argv) { // Initialize the window. glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowSize(WIDTH, HEIGHT); // Set shading model. glShadeModel(GL_SMOOTH); // Create the window. this->mainWindow = glutCreateWindow(TITLE); // Set keyboard methods. glutKeyboardFunc(&onKeyDownCallback); glutKeyboardUpFunc(&onKeyUpCallback); glutSpecialFunc(&onSpecialKeyDownCallback); glutSpecialUpFunc(&onSpecialKeyUpCallback); // Set mouse callbacks. glutMouseFunc(&onMouseButtonCallback); #ifdef FREEGLUT glutMouseWheelFunc(&onMouseWheelCallback); #endif glutMotionFunc(&onMouseMotionCallback); glutPassiveMotionFunc(&onMousePassiveMotionCallback); // Set display callbacks. glutDisplayFunc(&onDrawCallback); glutReshapeFunc(&onReshapeCallback); // Set a timer to control the frame rate. glutTimerFunc(FRAME_PERIOD, onTimerTickCallback, 0); // Set clear color. glClearColor(1.0f, 1.0f, 1.0f, 1.0f); Camera::getInstance()->subscribe(this); // Initialize texture loader. TextureLoader::initialize(); } 

La imagen que estoy usando ya funcionó para otro proyecto OpenGL / DevIL, por lo que no puede ser la fuente del problema.

La textura se crea dentro de cada clase que representa un objeto mundial (es un juego …). El personaje se llama Blobby y aquí están las partes más importantes de su implementación:

 #include "Blobby.h" Blobby::Blobby() { this->isJumping = false; this->isRotating = false; this->isWalking = false; this->isDucking = false; this->isStandingUp = false; this->isOnGround = false; this->isTouchingWall = false; this->angle = 0; this->direction = DIRECTION_UNKNOWN; this->wallDirection = DIRECTION_UNKNOWN; // Create a red blobby texture. this->texture = TextureLoader::createTexture(L"D:/01.bmp", new Color(255, 0, 0)); ContactListener::getInstance()->subscribe(this); } void Blobby::draw() { GraphicsEngine::drawString(35, 40, "isOnGround = %s", this->isOnGround ? "true" : "false"); GraphicsEngine::drawString(35, 55, "inJumping = %s", this->isJumping ? "true" : "false"); GraphicsEngine::drawString(35, 70, "isRotating = %s", this->isRotating ? "true" : "false"); GraphicsEngine::drawString(35, 85, "isTouchingWall = %s (%i)", this->isTouchingWall ? "true" : "false", this->wallDirection); Texturizer::draw(this->texture, this->getBody(0)->GetPosition().x, this->getBody(0)->GetPosition().y, this->getBody(0)->GetAngle()); AbstractEntity::draw(); // draws debug information... not important } 

La callback del temporizador OpenGL llama a un método de paso que termina aquí:

 void Simulator::step() { // Update physics. this->gameWorld->step(); b2Vec2 p = Camera::convertWorldToScreen(meter2pixel(this->cameraBlobby->getBody(0)->GetPosition().x), 300.0f); if (px setViewCenter(Camera::convertScreenToWorld(400 - (300 - int(px)), 300)); } else if (px > 500) { Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 + (int(px) - 500), 300)); } for (unsigned int i = 0; i gameWorld->getEntityCount(); i++) { IEntity *entity = this->gameWorld->getEntity(i); entity->draw(); } } 

IEntity es una clase virtual pura (es decir, una interfaz), AbstractEntity implementa esta interfaz y agrega métodos globales. Blobby hereda de AbstractEntity y agrega rutinas que son especiales para este objeto mundial.

EDITAR: He subido una versión más reciente del código (todo el proyecto, incluidas las dependencias) aquí: http://upload.visusnet.de/uploads/BlobbyWarriors-rev19.zip (~ 9.5 MB)

No estoy familiarizado con DevIL, pero … ¿está proporcionando el color difuso correcto para sus vértices? Si la iluminación está habilitada, ¿hay algunas luces que apuntan en el patio? ¿La cámara mira la parte frontal del quad?

EDITAR:

Obtuvo un error en el código, pero no en el que publicó aquí, sino en la versión en el archivo que vinculó.

Llama a glColor3i(255, 255, 255) , y establece el color difuso en (casi) el negro como se esperaba. glColor3i no acepta los valores de color en el rango objective (cálculo o framebuffer). Los valores posibles se escalan a todo el rango del tipo int . Esto significa que el valor máximo (1.0 en flotación) está representado por MAX_INT (2,147,483,647), 0 es 0 y -1.0 es MIN_INT (-2,147,483,648). El valor 255 que proporcionó representa alrededor de 0.000000118, que es casi cero.

Creo que pretendías una de las siguientes formas (completamente equivalentes):

glColor3f(1.0, 1.0, 1.0) , glColor3ub(255, 255, 255) ,

glColor3i(2147483647, 2147483647, 2147483647) .

¿Qué hay en la matriz b2Mat22? Podría ser que la multiplicación por esta matriz esté provocando que sus vértices se dibujen en el sentido de las agujas del reloj, porque creo que en ese caso la parte posterior de su cuadrado estaría frente a usted, y la textura podría estar en el otro lado (invisible).

Tuve un problema como este hace mucho tiempo, creo que en aquel entonces era un problema porque las dimensiones de la textura no eran un exponente de 2 (128×128, 512×512, etc.). Estoy seguro de que ya lo han arreglado, pero podría ser algo para intentarlo.