OpenGL重复调用glTexImage2D和alpha混合

OpenGL重复调用glTexImage2D和alpha混合,opengl,alphablending,glteximage2d,visual-artifacts,Opengl,Alphablending,Glteximage2d,Visual Artifacts,这与其说是出于实际目的,不如说是出于好奇:OpenGL规范中是否有任何内容表明多次调用glTexImage2D是非法的?我的意思是非法,因为“它可能产生错误的结果”,而不仅仅是效率低下(假设我不关心不使用glTexSubImage2D对性能的影响) 我问这个问题的原因是,我在绘制重叠的纹理贴图基本体时注意到一些非常奇怪的瑕疵,这些基本体使用部分透明的纹理,使用glTexImage2D(参见附图)每帧加载一次纹理:几秒钟后(即几百帧),小的矩形黑色补丁出现在屏幕上(它们实际上在连续帧之间的黑色和法

这与其说是出于实际目的,不如说是出于好奇: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);
}
#包括
#苹果__
#包括
#包括
#否则
#包括
#包括
#恩迪夫
/*几个函数使用的一些常量和变量*/
常数整型宽度=640;
const int height=480;
#定义texSize 64
GLuint vbo;
胶合特克斯;
/*正向声明,创建随机纹理;如果需要,则使用glTexSubImage2D
更新为非零(否则为glTexImage2D)*/
void createTexture(GLuint标签,int更新);
int init()
{
/*SDL初始化*/
if(SDL_Init(SDL_Init_视频)<0)
返回0;
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
如果(!SDL_SetVideoMode(宽度、高度、0、SDL_OPENGL)){
fprintf(stderr,“无法初始化OpenGL”);
返回0;
}
/*OpenGL初始化*/
glClearColor(0,0,0,0);
glEnable(GL_纹理_2D);
glEnable(GL_混合物);
glBlendFunc(GL_ONE,GL_ONE减去SRC_ALPHA);
glViewport(0,0,宽度,高度);
glMatrixMode(GL_投影);
glLoadIdentity();
格洛托(0,宽度,高度,0,-1,1);
glMatrixMode(GLU模型视图);
/*创建VBO和纹理*/
glGenBuffers(1,&vbo);
glBindBuffer(GL_数组_BUFFER,vbo);
glBufferData(GLU数组缓冲区,1024,0,GLU动态绘图);
glGenTextures(1和tex);
createTexture(tex,0);
glEnableClientState(GL_顶点_数组);
glEnableClientState(GL_纹理_坐标_阵列);
返回1;
}
/*在指定点绘制三角形*/
空心拉伸三角形(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_数组_BUFFER,0,sizeof(coords1),coords1);
glVertexPointer(2,GL_FLOAT,4*sizeof(GLfloat),(void*)0;
glTexCoordPointer(2,GL_浮点,4*sizeof(GLfloat),
(char*)0+2*sizeof(GLfloat));
gldrawArray(GL_三角形,0,3);
}
void render()
{
glClear(GLU颜色缓冲位);
牵引三角(250,50);
createTexture(tex,0);
牵引三角(260、120);
SDL_GL_SwapBuffers();
}
空洞清理()
{
gldelete纹理(1和tex);
glDeleteBuffers(1和vbo);
SDL_退出();
}
int main(int argc,char*argv[])
{
SDL_事件;
如果(!init())返回1;
而(1){
while(SDL_事件和事件))
if(event.type==SDL\u QUIT)
返回0;
render();
}
清理();
返回0;
}
void createTexture(GLuint标签,int更新)
{
GLubyte数据[texSize*texSize*4];
GLubyte*p;
int i,j;
glBindTexture(GL_纹理_2D,标签);
对于(i=0;i4?255:0);
p[1]=((j%8)>4?255:0);
p[2]=((i%8)>4?255:0);
p[3]=255-i*3;
}
}
如果(!更新)
GLTEXAGE2D(GL_纹理_2D,0,GL_RGBA8,texSize,texSize,0,GL_RGBA,
GL_无符号字节,数据);
其他的
glTexSubImage2D(GL_纹理_2D,0,0,texSize,texSize,GL_RGBA,
GL_无符号字节,数据);
glTexParameteri(GL_纹理2D、GL_纹理最小过滤器、GL_线性);
glTexParameteri(GL_纹理2D、GL_纹理MAG_过滤器、GL_线性);
}
注:

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

  • 如果我对每一帧使用
    glTexSubImage2D
    (在
    createTexture
    中使用
    update=1
    ),则瑕疵会消失

  • 如果我禁用混合,就不会有更多的工件

  • 我已经在2010年末的MacBookAir上测试过了,尽管我怀疑这是否特别相关


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

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

    只是出于兴趣。。。如果将createTexture移动到第一个Draw三角形之前。。。它有用吗?(我怀疑驱动程序的纹理同步路径中有错误)@Goz如果我将
    createTexture
    移动到两个
    drawTriangle
    s之前,问题就会消失。我想我真的没有考虑到司机的错误。。。如果有机会,我会在其他几个系统上尝试这段代码。基本上,它看起来像是系统正在更新纹理,而上一次绘制调用仍然在使用它。我猜禁用alpha blend会影响渲染路径,使其在上一次绘制过程中纹理不会发生变化。过去写过驱动程序,这是一个相当基本的错误(而且很容易犯)。你最好的办法是克服它,接受它超出你的控制。仍然值得向苹果发布这个bug,希望他们能修复驱动程序!我在Linux机器上测试了这一点,但没有出现工件,支持这可能是驱动程序中的一个bug的想法。有趣的是,当我在macbook air上的虚拟机上运行Linux下的程序时,这些工件也不会出现…只是出于兴趣。。。如果将createTexture移动到第一个Draw三角形之前。。。它有用吗?(我怀疑司机的车里有窃听器