半透明贴图的关键是贴图要包含Alpha通道,即贴图像素格式为RGBA格式。但普通BMP图像是没有Alpha通道的,所以需将像素格式进行转换。也很简单,就是在 RGB数据后再加一个字节,将3字节变为4字节。
/******************************************************************************/
//读取一个BMP文件作为纹理。如果失败,返回0,如果成功,返回1
//alpha值取0~255,0 为完全透明。255为不透明
/******************************************************************************/
bool Draw::LoadTexture(LPTSTR szFileName, GLuint &TextureId, GLint alpha)
{
HBITMAP hBMP;
BITMAP BMP;
GLint Index, Pixels;
GLubyte* PixelsData = NULL;
//生成新的纹理编号
glGenTextures(1, &TextureId);
if(TextureId == 0 ) return false;
hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
if (!hBMP) return false; // 装载图像
GetObject(hBMP, sizeof(BMP), &BMP); // 填充数据
Pixels = BMP.bmWidth * BMP.bmHeight; //像素总数
PixelsData = (GLubyte*)malloc(Pixels * 4); //申请内存
if(PixelsData == NULL) return false;
//复制数据
for(Index = 0; Index < Pixels; Index++)
{
memcpy(PixelsData + (Index * 4), (GLubyte*)BMP.bmBits + (Index * 3), 3);
PixelsData[(Index * 4) + 3] = alpha; //加入Alpha通道
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
//绑定纹理号
glBindTexture(GL_TEXTURE_2D, TextureId);
//设置滤镜
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_WRAP_S, GL_REPEAT); //在s方向上的缠绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //在t方向上的缠绕方式
//生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, BMP.bmWidth, BMP.bmHeight, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, PixelsData);
free(PixelsData); //释放内存
DeleteObject(hBMP); //释放图像
return true;
}
这样得到的贴图就是有Alpha通道的了。贴图使用方法如下:(以画球体为例)
GLfloat ConstColor[4] = {0.0f, 0.0f, 0.0f, 1.0f}; //颜色控制
UINT Texture;
//初始化时装载贴图
void Init()
{
.......
//创建贴图
char szOptionPath[MAX_PATH];
strcpy_s(szOptionPath, _T("\\map\\stone1.bmp"));
LoadTexture(szOptionPath, Texture, 128);
......
};
/******************************************************************************/
// 绘制球体 Balldx = 球编号
/******************************************************************************/
void Draw::DrawBall(int Balldx )
{
int nIndex;
float *pfAngel;
//座标复位
glLoadIdentity();
glPushAttrib(GL_CURRENT_BIT);
glPushMatrix(); //把矩阵压入堆栈
//确定球的位置
if(Balldx == 1)
glTranslatef(-0.5f, 0.0f, -1.0f);
else
glTranslatef(0.5f, 0.0f, -1.0f);
// 绘制球体, 第1、2、3个参数分别表示半径,经度线数、纬度线数
glDepthMask(GL_FALSE); //关掉深度测试
glEnable(GL_BLEND); //开混合模式贴图
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //设置混合方式
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture); //使用纹理
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND); //贴图模式为混合
if(Balldx == 1)
{
//红色
ConstColor[0] = 1.0f;
ConstColor[1] = 0.0f;
ConstColor[2] = 0.0f;
}
else
{
//蓝色
ConstColor[0] = 0.0f;
ConstColor[1] = 0.0f;
ConstColor[2] = 1.0f;
}
ConstColor[3] = 0.5f;
glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR, ConstColor);
// 绘制
gluQuadricTexture(QuadricObj, GL_TRUE);
gluSphere(QuadricObj, 2.5f, 50, 50); //实体
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
glPopMatrix();
glPopAttrib();
}
效果演示: