【问题标题】:Broken texture number OpenGL, after glGenTextures/glBindTexture在 glGenTextures/glBindTexture 之后损坏的纹理编号 OpenGL
【发布时间】:2013-09-06 15:48:44
【问题描述】:

我的一个纹理在 OpenGL 上的行为很糟糕。

删除纹理后,我创建了一个新的,它生成的tex编号与以前相同,但纹理不正确。而且 glGetError 在每一行都返回 0 !我试图在 glDeleteTextures 之后添加 glFlush/glFinish 但它没有改变任何东西!纹理编号似乎锁定在某个地方...为什么?

它是单线程的,这里的行为:

//myTexture == 24 is loaded and works correctly
GLboolean bIsTexture = glIsTexture(myTexture); //returns 1 = > ok
glDeleteTextures(1,&myTexture);
bIsTexture = glIsTexture(myTexture); //returns 0 => ok

//Let's create a new texture
glGenTextures(1,&myTexture);//myTexture == 24 (as the glDelete was ok)
glBindTexture(GL_TEXTURE_2D,myTexture);     
bIsTexture = glIsTexture(myTexture); //returns 0 => FAILS

【问题讨论】:

  • 这是我复制/粘贴的错误,现在可以了
  • 仅供参考,为了测试这样的案例,在两次调用之间手动将 myTexture 设置为不同的值(可能是 max uint)可能是个好主意,以确保 myTexture 确实设置为相同第二次通话中的号码,而不是“什么都不做”。

标签: c++ opengl opengl-es


【解决方案1】:

在创建已经绑定的纹理之前调用 BindTexture 为 0:

//Let's create a new texture
glBindTexture(GL_TEXTURE_2D,0); // free the old bind texture if deleted
glGenTextures(1,&myTexture);//myTexture == 24 (as the glDelete was ok)
glBindTexture(GL_TEXTURE_2D,myTexture);     
bIsTexture = glIsTexture(myTexture); //returns 1 => Ok

【讨论】:

  • 我遇到了同样的问题; OpenGL回收了一个纹理名称(删除旧纹理并生成新纹理后),GL没有报错,但是纹理在游戏中显示为空白。以上解决了我的问题。
【解决方案2】:

好吧,您在创建新纹理的常用操作序列中遗漏了一个重要步骤:实际分配它。

//Let's create a new texture

glGenTextures(1,&myTexture);//myTexture == 24 (as the glDelete was ok)
glBindTexture(GL_TEXTURE_2D,myTexture);     

这里你必须调用 glTexImage2D 或 glTexStorage 来实际分配纹理对象。在此之前,没有与生成的纹理 name 关联的纹理 data。这很重要:glGenTextures 生成的值不是 textures,而是纹理 names(即句柄),而 OpenGL 声明这应该已经是一个纹理对象,错误的驱动程序可能会错误地解释它。

glTexImage2D(…); // <<<<<
bIsTexture = glIsTexture(myTexture); //returns …

更新:

正如 Andon M. Coleman 指出的那样(感谢),将纹理名称绑定到纹理目标会生成纹理对象(与所述名称相关联)。所以人们应该期望 glIsTexture 在这种情况下返回 GL_TRUE 。现在,现实与理想的规范世界有何不同:实际的(有缺陷的)驱动程序可能会被错误地实现,并且仅在存在实际数据存储时才假定名称与纹理对象相关联,因此可能有必要进行实际操作分配看看效果。

实际上,您通常在名称分配后很快就进行存储分配。我假设您的驱动程序的实现者使用的测试套件不会检查这种极端情况。是时候写一个错误报告了。

【讨论】:

  • 根据 OpenGL 规范。纹理名称在绑定时与对象相关联。由于glIsTexture (...) 仅测试名称是否与纹理相关联,因此为纹理分配存储应该无关紧要。仅绑定纹理的行为就足够了。
  • @AndonM.Coleman:查看我的答案更新。请注意,即使在我最初的答案中,我也将 glIsTexture 的返回值留待确定。
  • 其实我已经用glTexImage2D检查过,纹理加载没有错误,但是当我绘制它时,它是空的。这不可能是驱动程序问题,因为它在 Windows 和 Android 上存在问题...
  • @Poppyto: 嗯,当你调用 glDeleteTextures 时,会不会是纹理仍然绑定在某个纹理单元目标中?如果您在删除之前调用glBindTexture(GL_TEXTURE_2D, 0); 会发生什么?如果您所经历的行为是否有效,我必须仔细阅读规范。但请试一试。
  • @Poppyto:好吧,规范禁止您遇到的情况:在纹理名称上调用 glDeleteTextures 意味着 OpenGL 进入一种状态,就好像它的所有纹理单元目标都调用了 glBindTexture(..., 0)一定会。所以调用 glBindTexture(..., newOldID) 应该创建一个新的纹理目标。现在我不会排除两个驱动程序中存在相同的错误,但我也怀疑存在状态缓存机制(可能在那个 CGL 中),“哦 glBindTexture(..., 24) – 这已经绑定了,我”我不再用那个调用 glBindTexture”。
【解决方案3】:

glIsTexture (...) 唯一要做的就是让您知道 OpenGL 名称(句柄)是否属于纹理。事实上,直到第一次使用 OpenGL 名称才真正与其最终用途相关联。对于您的纹理名称,glIsTexture 仅检查名称是否与纹理相关联;当您第一次使用该名称呼叫glBindTexture (...) 时,就会发生这种关联。 glIsTexture告诉你这个名字是否有关联的数据存储(例如你叫glTexImage2D (...)或在OpenGL 4+中glTexStorage (...))。

这里有一个有趣的琐事:在 OpenGL 3.0 之前,规范。允许您为对象名称提供任何未使用的数字,OpenGL 会将其视为您使用glGen___ (...) 函数生成名称;这仍然可以在兼容性配置文件中完成。这就是名称生成功能在宏伟计划中的重要性。

这里最重要的一点是,名字在使用时就被赋予了它们的功能。更重要的是glIs___ (...) 仅告诉您名称是否与特定类型的 OpenGL 对象相关联(而不是如果它是有效/已初始化/...对象)。


我刚才提到的官方解释来自OpenGL规范,其中指出:

命令:

void GenTextures( sizei n, uint *textures );

在纹理中返回 n 个以前未使用的纹理名称。这些名称被标记为已使用,仅用于 GenTextures,但它们仅在 首次绑定时才获得纹理状态和维度,就像它们未使用一样。

绑定是通过调用实现的:

void BindTexture( enum target, uint texture );

将目标设置为所需的纹理目标,并将纹理设置为未使用的名称。生成的纹理对象是一个新的状态向量,包含所有状态并具有第 8.21 节中列出的相同初始值。绑定到目标的新纹理对象是,并且仍然是目标指定的维度和类型的纹理,直到它被删除。



由于这是glIsTexture (...) 应该做的所有,我不得不假设这是一个驱动程序错误。

【讨论】:

  • 感谢您的回答,但这不可能是驱动程序问题,因为它在 Windows、Android 和 iOS 上都有问题,一定有一个技巧......!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2018-10-18
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
相关资源
最近更新 更多