OpenGL 无效的纹理或状态

Posted

技术标签:

【中文标题】OpenGL 无效的纹理或状态【英文标题】:OpenGL Invalid Texture or State 【发布时间】:2014-12-22 19:20:25 【问题描述】:

我们正在 OpenGL 应用程序中开发 C++ 插件。应用程序将根据需要在我们的插件上调用“渲染”方法。在渲染我们的纹理时,我们注意到有时 一些 纹理被绘制成完全白色,即使它们是使用有效数据创建的。哪种纹理和何时出现似乎是随机的。在调查可能导致某些纹理呈现白色的原因时,我注意到简单地尝试检索纹理的大小(即使对于正确渲染的纹理)是行不通的。以下是创建纹理并检索其大小的简单代码:

GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0,
             GL_BGRA, GL_UNSIGNED_BYTE, imageDdata);

// try to lookup the size of the texture
int textureWidth = 0, textureHeight = 0;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &textureWidth);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &textureHeight);

glBindTexture(GL_TEXTURE_2D, 0);

输入到 glTexImage2D 的图像宽度和高度是 1536 x 1536,但是从 glGetTexLevelParameter 返回的值是 16384 x 256。事实上,我传递给 glTexImage2D 的任何宽度和高度图像都会导致输出 16384 x 256。如果我通过了 64 x 64 的宽度和高度,我仍然返回 16384 x 256。

我在另一个独立的测试应用程序中使用了相同的简单纹理加载/渲染代码,并且它一直都能正常工作。但是,当我在这个更大的应用程序中使用代码时,我得到了这些白色纹理。我还验证了 glGetError() 返回 0。

我假设包含应用程序正在设置一些 OpenGL 状态,这会在我们尝试渲染纹理时导致问题。对于可能导致这些白色纹理或纹理尺寸无效的检查事项,您有什么建议吗?

更新 我正确渲染的测试应用程序和未正确渲染的集成应用程序都在启用了加速 3D 图形的 Windows 7 上的 VM 中运行。这是虚拟机环境: CentOS 7.0 OpenGL 2.1 台面 9.2.5

【问题讨论】:

您使用的是哪个平台,遇到错误时GL的上下文版本是什么? 谁他妈的投票结束了这个完美的问题? @MuertoExcobito CentOS 7.0 和 OpenGL 2.1 通过 Mesa 9.2.5 这些调用是直接按这个顺序执行的吗?意思是,glGetTexLevelParameteriv()glTexImage2D() 之后立即 被调用?还是为了简洁而省略了这些调用之间的任何内容? 为此构建一个小测试并检查您的应用程序中是否存在错误。这应该不难。如果测试失败,请在具有最新驱动程序的本机显卡上运行它。如果这仍然失败,您的测试可能是错误的。如果原生卡工作正常,那么 Mesa 中可能存在错误。老实说,我不知道 Mesa 在 VM 主机中模拟 3d 加速方面的工作原理,但我认为这不是主要用例,所以我想说你现在是该领域的首席开发人员。 【参考方案1】:

在调用此代码时,您是否检查过有效的 OpenGL 上下文处于活动状态? 您返回的值可能是未初始化的垃圾留在变量中,如果 glGetTexLevelParameter 由于某种原因失败,则不会修改这些值。 请注意 glGetErrors如果没有 OpenGL 上下文处于活动状态,em> 可能会返回 GL_NO_ERROR

要检查是否存在 OpenGL 上下文,请使用 wglGetCurrentContext (Windows)、glXGetCurrentContext (X11 / GLX) 或 CGLGetCurrentContext (MacOS X CGL)查询活动的 OpenGL 上下文;如果没有活动,所有这些函数都将返回 NULL。


仅供参考:您应该使用 GLint 从 OpenGL 检索整数值,原因是 OpenGL 类型具有非常特定的大小,可能与同名的原始 C 类型不同。例如,C unsigned int 的大小可能在 16 到 64 位之间变化,而 OpenGL GLuint 始终固定为 32 位。

【讨论】:

是的,我验证 glXGetCurrentContext() 返回一个非空指针。使用 GLint 的好处。 这是不正确的。在 Windows 中,在设置当前上下文之前调用 glGetError(),你会得到一个返回值 1282 (GL_INVALID_OPERATION)。 GL 的文档通常没有说明当您在没有上下文的情况下调用任何 GL 函数(包括 glGetError)时会发生什么,并且在某些平台上它只会崩溃。因此,我强烈建议不要依赖这种行为。 @MuertoExcobito:对不起,我的意思是写“可能会回来……”。无论如何,如果没有 OpenGL 上下文,它肯定不会崩溃。 glGetError 不是扩展函数,并且已被指定为所有操作系统的核心 OpenGL ABI(不要与 API 混淆)的一部分。特别是在 OpenGL 上下文之外调用的确切返回代码将是未定义的。 -- 无论如何,我建议不要依赖 glGetError 返回代码来确定周围是否存在有效的 OpenGL 上下文。 OP 在调用 glGet*() 之前将变量初始化为 0。因此,如果调用出于某种原因未提供值,则调用后它们将为 0。 @RetoKoradi:好吧,那我没主意了;好吧,除了主机应用程序可能假设 OpenGL-2.x 或更早版本并进行自己的纹理名称管理,绕过 glGenTextures。插件可能会生成它自己的纹理名称,但主机只使用相同的纹理名称,并破坏插件的纹理对象;这是我留下的唯一想法。【参考方案2】:

https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetTexLevelParameter.xml

glGetTexLevelParameter 返回活动纹理单元的纹理级别参数。

在所有设备上尝试glActiveTexture。看看你是否得到了默认值。

【讨论】:

并且glBindTexture() 将纹理绑定到活动纹理单元。因此,哪个纹理单元处于活动状态并不重要。除非在调用之间执行了其他代码。 是的。更多代码会有所帮助。但也许默认纹理是绑定的。 TBH 我会在运行 MESA u 的 VM 之外测试我的应用程序

以上是关于OpenGL 无效的纹理或状态的主要内容,如果未能解决你的问题,请参考以下文章

如何在OpenGL中反转纹理颜色

OpenGL设置纹理图片

OpenGL设置纹理图片

OpenGL glUniform1i 无效操作

使用 OpenGL 调整图像大小

如果当前处于活动状态,则 OpenGL 纹理不会渲染