【问题标题】:OpenGL repeated calls to glTexImage2D and alpha blendingOpenGL 重复调用 glTexImage2D 和 alpha 混合
【发布时间】:2012-12-15 01:24:13
【问题描述】:

这更多是出于好奇而不是出于任何实际目的:OpenGL 规范中是否有任何内容表明多次调用glTexImage2D(例如,每帧一次)是非法的?我的意思是非法的,因为它可能会产生错误的结果,而不仅仅是效率低下(假设我不在乎不使用 glTexSubImage2D 对性能的影响)。

我问的原因是,我在绘制重叠的纹理映射图元时注意到一些非常奇怪的伪影,这些图元使用部分透明的纹理,每帧使用 glTexImage2D 加载一次(见附图):几秒钟后(即几百帧),屏幕上出现小的矩形黑色斑块(它们实际上在连续帧之间在黑色和正常之间翻转)。

我在下面附上了我可以编写的最简单的示例代码,它显示了这个问题。

#include <stdio.h>

#ifndef __APPLE__
# include <SDL/SDL.h>
# include <SDL/SDL_opengl.h>
#else
# include <SDL.h>
# include <SDL_opengl.h>
#endif

/* some constants and variables that several functions use */
const int width = 640;
const int height = 480;
#define texSize 64

GLuint vbo;
GLuint tex;

/* forward declaration, creates a random texture; uses glTexSubImage2D if 
   update is non-zero (otherwise glTexImage2D) */
void createTexture(GLuint label, int update);

int init() 
{
  /* SDL initialization */
  if (SDL_Init(SDL_INIT_VIDEO) < 0)
    return 0;

  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  if (!SDL_SetVideoMode(width, height, 0, SDL_OPENGL)) {
    fprintf(stderr, "Couldn't initialize OpenGL");
    return 0;
  }

  /* OpenGL initialization */
  glClearColor(0, 0, 0, 0);
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_BLEND);
  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, width, height, 0, -1, 1);
  glMatrixMode(GL_MODELVIEW);

  /* creating the VBO and the textures */
  glGenBuffers(1, &vbo);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);
  glBufferData(GL_ARRAY_BUFFER, 1024, 0, GL_DYNAMIC_DRAW);

  glGenTextures(1, &tex);
  createTexture(tex, 0);

  glEnableClientState(GL_VERTEX_ARRAY);
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);

  return 1;
}

/* draw a triangle at the specified point */
void drawTriangle(GLfloat x, GLfloat y)
{
  GLfloat coords1[12] = {0, 0, 0, 0, /**/200, 0, 1, 0, /**/200, 150, 1, 1};

  glLoadIdentity();
  glTranslatef(x, y, 0);

  glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(coords1), coords1);
  glVertexPointer(2, GL_FLOAT, 4*sizeof(GLfloat), (void*)0);
  glTexCoordPointer(2, GL_FLOAT, 4*sizeof(GLfloat),
    (char*)0 + 2*sizeof(GLfloat));

  glDrawArrays(GL_TRIANGLES, 0, 3);
}

void render()
{
  glClear(GL_COLOR_BUFFER_BIT);

  drawTriangle(250, 50);

  createTexture(tex, 0);
  drawTriangle(260, 120);

  SDL_GL_SwapBuffers();
}

void cleanup()
{
  glDeleteTextures(1, &tex);
  glDeleteBuffers(1, &vbo);

  SDL_Quit();
}

int main(int argc, char* argv[])
{
  SDL_Event event;

  if (!init()) return 1;

  while (1) {
    while (SDL_PollEvent(&event))
      if (event.type == SDL_QUIT)
        return 0;

    render();
  }

  cleanup();

  return 0;
}

void createTexture(GLuint label, int update)
{
  GLubyte data[texSize*texSize*4];
  GLubyte* p;
  int i, j;

  glBindTexture(GL_TEXTURE_2D, label);

  for (i = 0; i < texSize; ++i) {
    for (j = 0; j < texSize; ++j) {
      p = data + (i + j*texSize)*4;
      p[0] = ((i % 8) > 4?255:0);
      p[1] = ((j % 8) > 4?255:0);
      p[2] = ((i % 8) > 4?255:0);
      p[3] = 255 - i*3;
    }
  }

  if (!update)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize, texSize, 0, GL_RGBA,
      GL_UNSIGNED_BYTE, data);
  else
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texSize, texSize, GL_RGBA,
      GL_UNSIGNED_BYTE, data);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

注意事项:

  1. 我正在使用 SDL,但我在 wxWidgets 中看到了同样的情况,所以这不是 SDL 相关的问题。

  2. 如果我对每一帧都使用glTexSubImage2D(在createTexture 中使用update = 1),伪影就会消失。

  3. 如果我禁用混合,就不会再有伪影了。

  4. 我一直在 2010 年末的 MacBook Air 上对此进行测试,但我怀疑这是否特别相关。

【问题讨论】:

  • 只是出于兴趣...如果您将 createTexture 移动到第一个 drawTriangles 之前...它有效吗? (我怀疑驱动程序的纹理同步路径中存在错误)
  • @Goz 如果我在两个drawTriangles 之前移动createTexture,问题就会消失。我想我并没有真正考虑过驱动程序中的错误......当我有机会时,我会在其他几个系统上尝试代码。
  • 基本上看起来系统正在更新纹理,而之前的绘制调用仍在使用它。我猜想关闭 alpha blend 会影响渲染路径,以至于在上一次绘制正在进行时没有发生纹理更改。过去编写驱动程序是一个非常基本(并且非常容易犯)的错误。你最好的办法是解决它并接受它超出你的控制。仍然值得将错误发布给苹果,希望他们能修复驱动程序!
  • 我在 Linux 机器上对此进行了测试,没有出现工件,支持了这可能是驱动程序中的错误的想法。有趣的是,当我在我的 macbook air 上的虚拟机中运行 Linux 下的程序时,这些工件也没有出现......

标签: opengl alphablending glteximage2d visual-artifacts


【解决方案1】:

这显然是一个 OpenGL 实现错误(只是在循环中调用 glTexImage2D 不会导致这种情况发生)。

【讨论】:

  • 这很好,这可能只是一个错误。很难注意到,因为大多数应用程序调用glTexImage2D 的频率远低于每帧一次...我将在更多系统上尝试此操作,看看它的重现性如何。
  • 这可能是正确的答案。为了获得一些支持,我在另一台机器(运行 Ubuntu Linux)上尝试了该程序,但看不到工件。此外,即使在 Macbook Air(运行 Ubuntu Linux 的虚拟机)上的虚拟机中运行程序时,伪影也会消失。
  • @Legendre17:感谢您的提醒。
猜你喜欢
  • 2015-03-30
  • 2011-12-14
  • 2013-11-16
  • 2011-05-16
  • 1970-01-01
  • 2015-07-25
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多