使用glTexImage2D的奇怪结果

Tho*_*mas 5 c++ opengl

我一直试图找出glTexImage2D工作方式,并从一些非常清晰的代码中看到一些奇怪的结果.我的代码简单地将粗略的圆圈绘制成256*256长度的无符号数组,然后将该数据发送出去以成为纹理.然而,无论我在图像创建循环中选择何种组合,显示的纹理都会变成红色和橙色的变化:

unsigned* data = new unsigned[256*256];
for (int y = 0; y < 256; ++y)
    for (int x = 0; x < 256; ++x)
        if ((x - 100)*(x - 100) + (y - 156)*(y - 156) < 75*75)
            data[256*y + x] = ((156 << 24) | (256 << 16) | (156 << 8) | (200 << 0));
        else
            data[256*y + x] = 0;  // I'd expect this to be transparent and the above to be slightly transparent and green, but it's red somehow.

glBindTexture(GL_TEXTURE_2D, texid);
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_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data);
Run Code Online (Sandbox Code Playgroud)

OpenGL选项:

    glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//glEnable(GL_BLEND);
//glDisable(GL_CULL_FACE);

glGenTextures(1, &leaf[0]);
    createLeaf(leaf[0]);  // createLeaf(GLuint& texid) is posted entirely above
Run Code Online (Sandbox Code Playgroud)

其余代码除了在窗口中的单个四边形上显示纹理外什么都不做.(x64 win7)

编辑:我完全尝试了Rickard的解决方案,我仍然得到一个紫色圆圈.

Nic*_*las 14

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)data);
Run Code Online (Sandbox Code Playgroud)

首先是积极的事情.您使用大小的内部格式(GL_RGBA8,而不是GL_RGBA).这是非常好的; 继续这样做.您清楚地了解内部格式(GL_RGBA8)和像素传输格式(GL_RGBA)之间的区别.这也很好.

问题是这个.你告诉OpenGL你的数据是无符号字节流.但它不是无符号字节流; 它是无符号整数流.这就是你宣布的方式data,这就是你如何填补data.那你为什么要骗OpenGL?

问题在于你的颜色.这是您的颜色值之一:

 ((156 << 24) | (256 << 16) | (156 << 8) | (200 << 0))
Run Code Online (Sandbox Code Playgroud)

首先,256不是有效颜色.十六进制的256是0x100,这是两个字节,而不是一个.

你可以得到的无符号整数是:

 0x9D009CC8
Run Code Online (Sandbox Code Playgroud)

如果这些按顺序是RGBA颜色,则红色为0x9D,绿色为0x00,蓝色为0x9C,alpha为0xC8.

现在,因为您可能正在使用小端计算机,所以翻转存储了4个字节,如下所示:

 0xC89C009D
Run Code Online (Sandbox Code Playgroud)

当你告诉OpenGL假装这是一个字节数组(它不是)时,你正在失去little-endian转换.因此OpenGL看到字节数组以0xC8开头,因此这是红色值.等等.

你需要告诉OpenGL你实际在做什么:你在一个无符号的32位整数中存储了四个8位无符号值.为此,请使用以下命令:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (GLvoid*)data);
Run Code Online (Sandbox Code Playgroud)

GL_UNSIGNED_INT_8_8_8_8表示您正在向OpenGL提供无符号32位整数数组(您就是这样).32位整数的前8位是红色,第二位是绿色,第三位是蓝色,第四位是alpha.

因此,要完全修复代码,您需要:

GLuint* data = new GLuint[256*256]; //Use OpenGL's types
for (int y = 0; y < 256; ++y)
    for (int x = 0; x < 256; ++x)
        if ((x - 100)*(x - 100) + (y - 156)*(y - 156) < 75*75)
            data[256*y + x] = ((0x9C << 24) | (0xFF << 16) | (0x9C << 8) | (0xC8 << 0));
        else
            data[256*y + x] = 0;  // I'd expect this to be transparent and the above to be slightly transparent and green, but it's red somehow.

glBindTexture(GL_TEXTURE_2D, texid);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);  //Always set the base and max mipmap levels of a texture.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, (GLvoid*)data);
Run Code Online (Sandbox Code Playgroud)

//我希望这是透明的,上面是略透明和绿色的,但不知何故它是红色的.

阿尔法并不意味着透明 ; 除非你赋予它意义,否则它根本没有任何意义.Alpha仅表示透明度,如果您使用混合并设置混合模式,导致低alpha使事物透明.否则,它根本没有任何意义.