我正在尝试编写一些能够在任意多边形上渲染任意图像的代码。该程序需要支持图像透明度。我选择使用OpenGL来渲染所述多边形。当我在Windows机器上开发时,我正在使用glew来处理在OpenGL 1.1之后发生的OpenGL函数。我的图形硬件支持OpenGL 2.1。我正在使用stb_image将我的图像从磁盘加载到RAM。我从绘图中得到了一些相当奇怪的结果。
当我在glTexEnv中使用GL_DECAL简单地将图像渲染到多边形上时,纹理的alpha通道决定了它在纹理颜色和绘制到的多边形颜色之间的混合。这是我的期望,但这不是我想要的行为。所以,我从GL_DECAL更改为GL_REPLACE,据说在与颜色缓冲区混合时使用纹理的alpha值。启用混合后,我得到了上面提到的奇怪结果。当我想要绘制的图像的alpha值等于0时,我在(据称)完全透明的部分中得到随机颜色。我的问题实际上与Transparent png texture in cocos2d using opengl iphone中提到的问题完全相同,但在Windows 7而不是iOS上。
有谁知道为什么我会得到这些结果以及我能做些什么来得不到这些结果?
使用glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
呈现的图片:
http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/gl_decal.png
注意小猫图像上的红色文本和红色背景。这是应该的。
使用glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
呈现的图片:
http://www.majhost.com/gallery/DagonEcelstraun/Others/HelpNeeded/gl_replace.png
请注意,文本不再是红色。奇。另请注意,小猫的背景没有意义。
初始化代码,在Graphics2D.cpp中:
Graphics2D::Graphics2D()
{
glEnable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
图像加载代码,在Graphics2D.cpp中:
int Graphics2D::loadImage( std::string imageName ) {
FILE *file = fopen( imageName.c_str(), "rb" ); //open filename as a read-only binary file
GLuint texture = 0;
int x, y, comp; //actual x-dimension, y-dimension, and number of byter per pixel in the actual file
GLubyte *data = stbi_load_from_file( file, &x, &y, &comp, 0 );
fclose( file );
glEnable( GL_TEXTURE_2D );
glGenTextures( 1, &texture );
glBindTexture( GL_TEXTURE_2D, texture );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
if( comp == 3 ) {
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, data );
} else if( comp == 4 ) {
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
}
ImageData d;
d.id = texture;
d.x = x;
d.y = y;
d.a = comp == 4;
images.push_back( d );
return texture;
}
图形绘制代码,在Graphics2D.cpp中:
void Graphics2D::drawImage( int imageID, int x, int y ) {
ImageData curData;
for( ImageData &id : images ) {
if( id.id == imageID ) {
curData = id;
}
}
int maxX = x + curData.x;
int maxY = y + curData.y;
if( curData.a ) {
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
} else {
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
}
glBindTexture( GL_TEXTURE_2D, imageID );
glBegin( GL_QUADS );
glTexCoord2i( 0, 0 );
glVertex3i( x, -y, -1 );
glTexCoord2i( 1, 0 );
glVertex3i( maxX, -y, -1 );
glTexCoord2i( 1, 1 );
glVertex3i( maxX, -maxY, -1 );
glTexCoord2i( 0, 1 );
glVertex3i( x, -maxY, -1 );
glEnd();
}
最后,主程序在Main.cpp中调用的代码:
void paint( HDC hDC )
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
//graphics.drawImage( catJPG, 0, 0 );
graphics.setColor( 255, 0, 0 ); //graphics is an object of type Graphics2D
graphics.drawImage( catPNG, 250, 250 );
graphics.drawText( "Hello World", 50, 50 );
glPopMatrix();
SwapBuffers( hDC );
}
让我解释一下我使用的数据结构:ImageData
是一个结构,其中包含一个用于OpenGL纹理id的int,一个用于纹理宽度的int(存储在x中),一个用于纹理的高度(存储在y中)和bool告诉我纹理是否有alpha通道(存储在a中)。因此,如果纹理具有alpha通道,则语句if( curData.a )
的计算结果为true。
值得注意的是,我在第一张和第二张图像之间唯一改变的是,在图像绘制功能中,我改变了'glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);' (现在是什么以及第二张图片中的内容)'glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);' (过去是什么以及第一张图片中的内容)。