【问题标题】:Texture binding isn't working / C++ / OpenGL [duplicate]纹理绑定不起作用/C++/OpenGL [重复]
【发布时间】:2017-10-18 22:26:47
【问题描述】:

我正在尝试为我的项目创建一个 Texture 类,用于初始化并从图像加载纹理。纹理加载良好,但每当我想通过调用 GetTexture() 函数从类外部获取纹理 ID 时,glIsTexture() 不再将返回值(纹理 ID)视为纹理。我想要纹理化的脸保持空白。

另外,我尝试使用函数 Texture::SetActive() 直接从 Texture 类本身将纹理与 glBindTexture() 绑定,但它仍然不起作用。

最后,当我直接从函数返回纹理 ID 时,纹理正确显示。

我在这里缺少什么吗?我现在真的不知道该寻找什么。

提前感谢您的帮助!

这是我的纹理类:

// Constructor
Texture::Texture(std::string const& texPath) {

    SDL_Surface *texture = nullptr, *newFormatTexture = nullptr, *flippedTexture = nullptr;
    SDL_PixelFormat tmpFormat;
    Uint32 amask, rmask, gmask, bmask;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN

    rmask = 0xFF000000;
    gmask = 0x00FF0000;
    bmask = 0x0000FF00;
    amask = 0x000000FF;

#else

    rmask = 0x000000FF;
    gmask = 0x0000FF00;
    bmask = 0x00FF0000;
    amask = 0xFF000000;

#endif

    if ((texture = IMG_Load(texPath.c_str())) == nullptr) {
        std::cerr << "[ERROR] : Could not load texture " << texPath << ". Skipping..." << std::endl;
    }

    tmpFormat = *(texture->format);
    tmpFormat.BitsPerPixel = 32;
    tmpFormat.BytesPerPixel = 4;
    tmpFormat.Rmask = rmask;
    tmpFormat.Gmask = gmask;
    tmpFormat.Bmask = bmask;
    tmpFormat.Amask = amask;

    if ((newFormatTexture = SDL_ConvertSurface(texture, &tmpFormat, SDL_SWSURFACE)) == nullptr)  {
        std::cerr << "[ERROR] : Couldn't convert surface to given format." << std::endl;
    }

    if ((flippedTexture = this->FlipSurface(newFormatTexture)) == nullptr) {
        std::cerr << "[ERROR] : Couldn't flip surface." << std::endl;
    }

    glGenTextures(1, &(this->_textureID));

    glBindTexture(GL_TEXTURE_2D, this->_textureID);

    glTexImage2D(GL_TEXTURE_2D, 0, 4, flippedTexture->w, flippedTexture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, flippedTexture->pixels);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);

    SDL_FreeSurface(flippedTexture);
    SDL_FreeSurface(newFormatTexture);
    SDL_FreeSurface(texture);

}

Texture::Texture(unsigned char *texData, int width, int height) {

    glGenTextures(1, &(this->_textureID));
    glBindTexture(GL_TEXTURE_2D, this->_textureID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texData);
    glBindTexture(GL_TEXTURE_2D, 0);

}

Texture::~Texture() {
    glDeleteTextures(1, &(this->_textureID));
}

Texture Texture::CreateTexture(std::string const& texPath) {

     Texture tex(texPath);
     return (tex);
}

Texture Texture::CreateTexture(unsigned char *texData, int width, int height) {

    Texture tex(texData, width, height);
    return (tex);
}

unsigned int Texture::GetTexture() const {
    return (this->_textureID);
}

void Texture::SetActive() {
    glBindTexture(GL_TEXTURE_2D, this->_textureID);
}

我加载和使用纹理的主类:

int WinMain(void) {

    Window window("Hello", 640, 480);
    double angleX, angleZ;
    Texture tex;
    int height;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(70, (double)640/480, 1, 1000);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);

    tex = Texture::CreateTexture("caisse.jpg");

    while (!window.Quit()) {

        Input::Update();

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(3,4,2,0,0,0,0,0,1);

        tex.SetActive();

        glBegin(GL_QUADS);

            glTexCoord2d(0, 1);
                 glVertex3d(1, 1, 1);

            glTexCoord2d(0, 0);
                 glVertex3d(1, 1, -1);

            glTexCoord2d(1, 0);
                 glVertex3d(-1, 1, -1);

            glTexCoord2d(1, 1);
                glVertex3d(-1, 1, 1);

        glEnd();

        glFlush();
        window.RefreshDisplay();
    }

    return (0);
}

编辑

我解决了我的问题。 如本主题所述:What are the usual troubleshooting steps for OpenGL textures not showing?,纹理的初始化不能在构造函数中完成。

感谢您的帮助:)

【问题讨论】:

  • 你为什么这样做:1)做很多this-&gt;_someName?将下划线放在前面的全部意义是让人们知道它是一个成员。 this-&gt; 毫无意义。 2)总是用括号括起来返回值?这实际上会抑制某些优化。

标签: c++ opengl binding textures


【解决方案1】:

好的,让我们看看这个:

Texture Texture::CreateTexture(std::string const& texPath) {

     Texture tex(texPath);
     return (tex);
}

我将假设这是一个静态函数。所以它在堆栈上创建了一个Texture 对象。而tex 包含一个 OpenGL 纹理对象。然后该函数返回此对象。

根据 C++ 的规则,tex 的生命周期仅限于创建它的范围。即Texture::CreateTexture。这意味着,在此函数结束时,tex 将通过调用其析构函数来销毁。

但是由于你返回了tex,在此之前,tex 将用于初始化函数的返回值。该返回值恰好是Texture 类型的对象,因此编译器将调用Texture 的复制构造函数来初始化返回值。

所以,在tex 被销毁之前,有两个Texture 对象:tex 本身和从tex 复制的Texture 类型的返回值。到目前为止,一切顺利。

现在,tex 被销毁了。 Texture::~Texture 在其中包含的纹理对象上调用 glDestroyTexture。这会破坏构造函数中创建的纹理。很好。

那么……现在会发生什么?好吧,让我们回到从CreateTexture 创建返回值的过程。我说它会调用Texture的复制构造函数来构造它,传递tex作为要复制的对象。

您没有发布完整的代码,但考虑到您编写的其他代码的性质,我敢打赌您没有编写Texture 的复制构造函数。没关系,因为编译器会为你制作一个。

只有这样不好。为什么?因为在 tex 被销毁之前,有两个 Texture 对象。并且两者存储相同的 OpenGL 纹理对象名称。这是怎么发生的?

因为您将纹理对象从tex 复制到返回值中。这就是编译器生成的复制构造函数所做的:它复制类中的所有内容。

所以当tex 被销毁时,它正在销毁OpenGL 纹理它刚刚返回

Texture 不应该是可复制的类。它应该是只能移动的,就像 C++ 中的许多包含资源的类一样。

【讨论】:

    猜你喜欢
    • 2020-10-28
    • 1970-01-01
    • 2021-05-04
    • 2012-12-11
    • 1970-01-01
    • 2012-03-13
    • 2013-09-07
    • 1970-01-01
    • 2013-04-21
    相关资源
    最近更新 更多