代码之家  ›  专栏  ›  技术社区  ›  Alexander Müller

OpenGL纹理显示为黑色

  •  1
  • Alexander Müller  · 技术社区  · 15 年前

    我试图将纹理应用到四边形,但我只得到一个黑框而不是纹理。我使用魔鬼从文件中加载图像,而OpenGL则完成其余的工作。

    以下是我目前正在做的工作:

    下面的类为图像抽象魔鬼表示。

    #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);
    }
    

    此类抽象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);
    }
    

    下面的类包含纹理加载过程。

    #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;
        }
    }
    

    最后一个类绘制。

    #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);
    }
    

    最后但并非最不重要的是,以下方法初始化OpenGL(并触发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();
    }
    

    我正在使用的图像已经为另一个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();
        }
    }
    

    IEntity是纯虚拟类(即接口),AbstractEntity实现此接口并添加全局方法。blobby继承了abstractEntity,并添加了这个世界对象特有的例程。

    编辑: 我在此处上载了代码的最新版本(整个项目包括依赖项): http://upload.visusnet.de/uploads/BlobbyWarriors-rev19.zip (约9.5 MB)

    3 回复  |  直到 15 年前
        1
  •  3
  •   slacker    15 年前

    我不熟悉魔鬼,但…是否为顶点提供正确的漫反射颜色?如果启用了照明,是否有一些灯光指向四边形?照相机能看到 前面 四边形的一边?

    编辑:

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

    你打电话来 glColor3i(255, 255, 255) ,并按预期将漫反射颜色设置为(非常接近)黑色。 glColor3i 接受目标(计算或帧缓冲区)范围内的颜色值。可能的值被缩放到 int 类型。这意味着最大值(1.0 in float)由max_int(2147483647)表示。 ,0为0,-1.0为最小整数(-2147483648)。这个 二百五十五 您提供的值约为0.000000118,几乎为零。

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

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

    glColor3i(2147483647, 2147483647, 2147483647) .

        2
  •  0
  •   Jordi    15 年前

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

        3
  •  0
  •   horatius83    15 年前

    很久以前我就遇到过这样的问题,我想当时的问题是纹理尺寸不是2的指数(128x128、512x512等)。我相信他们现在已经修好了,但这可能是值得尝试的。