C++ OpenGL纹理显示为黑色

C++ OpenGL纹理显示为黑色,c++,opengl,freeglut,devil,C++,Opengl,Freeglut,Devil,我试图将纹理应用于四边形,但我只得到一个黑框而不是纹理。我正在使用DevIL从文件中加载图像,其余的由OpenGL完成 以下是我目前正在做的事情: 下面的类抽象了图像的DevIL表示 #include "Image.h" Image::Image() { ilGenImages(1, &this->imageId); } Image::~Image() { ilDeleteImages(1, &this->imageId); } ILint Im

我试图将纹理应用于四边形,但我只得到一个黑框而不是纹理。我正在使用DevIL从文件中加载图像,其余的由OpenGL完成

以下是我目前正在做的事情:

下面的类抽象了图像的DevIL表示

#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" " << iluErrorString(error);
        }
        return false;
    }

    this->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" " << iluErrorString(error);
        }
        return false;
    }
    return true;
}

void Image::bind()
{
    ilBindImage(this->imageId);
}
下面的类包含纹理加载过程

#include "TextureLoader.h"

void TextureLoader::initialize()
{
    if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) {
        debug("Wrong DevIL version detected.");
        return;
    }

    ilInit();
    ilutRenderer(ILUT_OPENGL);
}

Texture* TextureLoader::createTexture(wchar_t *filename, Color *color)
{
    // Generate some space for an image and bind it.
    Image *image = new Image();
    image->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 < size * 4; i += 4)
    {
        if (imageData[i] == color->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 < size * 4; i += 4)
    {
        int rr = (int(imageData[i]) * int(color->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 < 255 ? rb : 255;

        imageData[i] = rr > 0 ? (GLubyte) rr : 1;
        imageData[i + 1] = rg > 0 ? (GLubyte) rg : 1;
        imageData[i + 2] = rb > 0 ? (GLubyte) rb : 1;
    }
}
我正在使用的图像已经用于另一个OpenGL/DevIL项目,因此它不可能是问题的根源

纹理是在表示世界对象(这是一个游戏…)的每个类中创建的。该角色称为Blobby,以下是其实现的最重要部分:

#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
}
OpenGL计时器回调调用一个步骤方法,该方法结束于:

void Simulator::step()
{
    // Update physics.
    this->gameWorld->step();

    b2Vec2 p = Camera::convertWorldToScreen(meter2pixel(this->cameraBlobby->getBody(0)->GetPosition().x), 300.0f);
    if (p.x < 300) {
        Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 - (300 - int(p.x)), 300));
    } else if (p.x > 500) {
        Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 + (int(p.x) - 500), 300));
    }


    for (unsigned int i = 0; i < this->gameWorld->getEntityCount(); i++) {
        IEntity *entity = this->gameWorld->getEntity(i);
        entity->draw();
    }
}
void模拟器::步骤()
{
//更新物理学。
这->游戏世界->步骤();
b2Vec2 p=Camera::convertWorldToScreen(米2像素(此->CamerabLobble->getBody(0)->GetPosition().x),300.0f);
如果(p.x<300){
Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400-(300-int(p.x)),300));
}否则,如果(p.x>500){
Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400+(int(p.x)-500),300));
}
对于(unsigned int i=0;igameWorld->getEntityCount();i++){
IEntity*entity=this->gameWorld->getEntity(i);
实体->绘图();
}
}
IEntity是一个纯虚拟类(即接口),AbstractEntity实现这个接口并添加全局方法。Blobby继承了AbstractEntity并添加了专门用于此世界对象的例程

编辑: 我在这里上传了代码的最新版本(整个项目包括依赖项):
(~9.5 MB)

b2Mat22矩阵中有什么?是不是乘以这个矩阵会导致顶点按顺时针顺序绘制,因为我认为在这种情况下,正方形的背面会朝向你,纹理可能在另一侧(不可见)。

我不熟悉DevIL,但是。。。是否为顶点提供了正确的漫反射颜色?如果启用了照明,是否有一些灯光指向四边形?摄像头是否注视四元显示器的前部

编辑: 代码中有一个bug,但不是你在这里发布的bug,而是你链接的存档中的版本

调用
glColor3i(255,255,255)
,它将漫反射颜色设置为(非常接近)预期的黑色
glColor3i
不接受目标(计算或帧缓冲区)范围内的颜色值。可能的值被缩放到
int
类型的整个范围。这意味着最大值(浮点值为1.0)由MAX_INT(2147483647)表示 ,0是0,-1.0是最小整数(-2147483648)。您提供的255值表示大约0.000000118,非常接近于零

我相信您打算采用以下形式之一(完全等效):

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


glColor3i(2147483647、2147483647、2147483647)
很久以前我就遇到过这样的问题,我想当时是纹理尺寸不是2的指数(128x128、512x512等)的问题。我确信他们现在已经解决了这个问题,但可能需要尝试。

b2Mat22只是一个矩阵,用于旋转顶点。此时它什么也不做(角度=0)。我通过将for循环重写为for(inti=3;I>=0;--I)来反转方向,但这也没有效果。然后我将1.0f和0.0f交换为texCoord{X,Y}(对于这两个循环):没有效果。我想问题出在别的地方。我在ILubyte*imageData=image->getData()行中添加了一个断点;imageData似乎没有指向任何地方,即指针似乎不正确。我添加了行imageData=ilGetData();并设置另一个断点。imageData似乎为空。能否显示实际执行TextureLoader::createTexture调用的代码,以及在何处执行Textureizer::draw调用?看起来你在创建纹理方面写了很好的错误处理,但是看看你是如何使用它的,这会有帮助。我已经在我的帖子中添加了你要求的代码。不,没有启用灯光。有没有办法检查摄像机是否正对着前方?然而,我认为这不是问题所在。我现在更进一步。它肯定会创建图像和纹理。我能够应用alpha混合,但我现在得到的不是我所期望的。颜色键起作用,但我只看到黑色图像的轮廓。我添加了一个指向完整项目档案的链接。请尝试添加
glColor3f(1.0、1.0、1.0)紧接着
glBegin(GL_QUADS)是的,就是这样。您忘记了此处发布的代码中的rogue
glColor3i()
调用,这是您在存档版本中进行的调用(该调用将颜色设置为黑色)
glColor3i
的工作方式与您想象的不一样。起初,我考虑过这个问题,但魔鬼应该解决这个问题。“DevIL允许使用任意大小的图像,但出于优化目的,OpenGL仅适用于尺寸为2次幂的图像。如果图像的尺寸不是2次幂,DevIL将在将图像发送到OpenGL之前调整图像大小。”请参阅
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();
}
#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
}
void Simulator::step()
{
    // Update physics.
    this->gameWorld->step();

    b2Vec2 p = Camera::convertWorldToScreen(meter2pixel(this->cameraBlobby->getBody(0)->GetPosition().x), 300.0f);
    if (p.x < 300) {
        Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 - (300 - int(p.x)), 300));
    } else if (p.x > 500) {
        Camera::getInstance()->setViewCenter(Camera::convertScreenToWorld(400 + (int(p.x) - 500), 300));
    }


    for (unsigned int i = 0; i < this->gameWorld->getEntityCount(); i++) {
        IEntity *entity = this->gameWorld->getEntity(i);
        entity->draw();
    }
}