在 OpenGL 中绘制多个 2D 纹理

Posted

技术标签:

【中文标题】在 OpenGL 中绘制多个 2D 纹理【英文标题】:Drawing multiple 2D textures in OpenGL 【发布时间】:2014-02-23 13:11:21 【问题描述】:

我正在使用 Visual Studio 2013 Ultimate 用 C++ 编写自己的游戏库。 我已经设法为 1 个纹理绘制了一些基本绘图,但是当我添加另一个纹理时,它似乎“覆盖”了前一个。

例如,如果我有纹理 A 和纹理 B,则 B 将被绘制到 A 应该在的位置。我已经检查过我没有为每个纹理使用相同的纹理 ID。

我查看了OpenGL trying to Draw Multiple 2d Textures, only 1st one appears,但这并没有解决我的问题。

我对 OpenGL 和一般较低级别的图形编程非常陌生,有人可以向我解释一下我的代码有什么问题吗?


这是我的纹理加载代码:

Texture::Texture(const std::string& filePath)

    m_pixelData = PixelData(stbi_load(filePath.c_str(),
                                      &m_size.x,
                                      &m_size.y,
                                      &m_numberOfImageComponents,
                                      0 /* number of requested image components if non-zero */));

    // generate 1 texture name and store it in m_textureName
    glGenTextures(1, &m_textureID);

    // make this the active texture
    glBindTexture(GL_TEXTURE_2D, m_textureID);

    // specifies how the data to be uploaded is aligned
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    // set texture parameters (need to look up the details of what's going on here)
    // TODO work out what this does
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    // TODO work out what this does
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

    GLenum imageFormat;

    // Work out image format
    // TODO add proper error handling
    switch(m_numberOfImageComponents)
    
    case 4:
        imageFormat = GL_RGBA;
        break;
    case 3:
        imageFormat = GL_RGB;
        break;
    default:
        DDGL_LOG(ERROR, "No image formats with " + std::to_string(m_numberOfImageComponents) + "components known");
        throw;
    

    // upload the texture to VRAM
    glTexImage2D(GL_TEXTURE_2D,
                0,
                imageFormat,
                m_size.x,
                m_size.y,
                0,
                imageFormat,
                GL_UNSIGNED_BYTE,
                m_pixelData.get());


这是我的“开始绘制”代码

void GraphicsAPIWrapper::startDraw()

    // TODO does this need to be called every frame?
    glMatrixMode(GL_PROJECTION); // select the matrix
    glLoadIdentity(); //reset the matrix

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


这是我的绘图代码

void GraphicsAPIWrapper::draw(std::shared_ptr<IDrawableGameObject> drawableObject)

        glPushMatrix();

        // convert pixel coordinates to decimals
        const Vector2F floatWindowSize          ((float) getWindowSize().x,                             (float) getWindowSize().y);
        const Vector2F floatObjectSize          ((float) drawableObject->getSize().x,                   (float) drawableObject->getSize().y);
        const Vector2F relativeObjectSize       (floatObjectSize.x / floatWindowSize.x,                 floatObjectSize.y / floatWindowSize.y);
        const Vector2F relativeObjectPosition   (drawableObject->getPosition().x / floatWindowSize.x,   drawableObject->getPosition().y / floatWindowSize.y);

        // transformations
        glTranslatef(relativeObjectPosition.x, relativeObjectPosition.y, 0.0f);
        glRotatef(drawableObject->getRotation(), 0.0f, 0.0f, 1.0f);

        // TODO should this be triangles or quads? I've been told triangles are generally higher performance
        // right now QUADS are simpler though
        glBegin(GL_QUADS);

        glBindTexture(GL_TEXTURE_2D, drawableObject->getTextureID());

        glTexCoord2f(0.0f, 1.0f); glVertex3f(-relativeObjectSize.x, -relativeObjectSize.y,  1.0f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(relativeObjectSize.x,  -relativeObjectSize.y,  1.0f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(relativeObjectSize.x,  relativeObjectSize.y,   1.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-relativeObjectSize.x, relativeObjectSize.y,   1.0f);

        glEnd();

        glPopMatrix();


这是我的“结束抽奖”代码

void GraphicsAPIWrapper::endDraw()

    glfwSwapBuffers(m_window->getWindow());


所以,为了非常清楚,我得到的行为是到处都绘制一个纹理,而不是根据需要绘制不同的纹理。

【问题讨论】:

【参考方案1】:

您在glBegin/glEnd-Block 内调用glBindTexture(),这是无效的,除了产生错误之外没有任何作用。因此,真正绑定的是在此之前的最后一个绑定 - 很可能是加载纹理时的绑定操作,所以最后一个加载的是所有对象显示的那个......

【讨论】:

谢谢!将 glBindTexture 移动到 glBegin 调用之前解决了我的问题。

以上是关于在 OpenGL 中绘制多个 2D 纹理的主要内容,如果未能解决你的问题,请参考以下文章

LWJGL OpenGL 不会绘制 2D 纹理

纹理不填充图形 - OpenGL

使用 OpenGL ES 2.0 绘制 2D 图像

OpenGL ES 渲染到纹理,然后绘制纹理

OpenGL 中的 2D 绘图:在原始尺寸下具有像素精度的线性过滤

基于OpenGL编写一个简易的2D渲染框架-04 绘制图片