废话!您不必使用多重纹理。只需预乘你的 alpha。
如果您在加载图像之后和为其创建 GL 纹理之前在图像上预乘 alpha,那么您只需要一个纹理单元用于 GL_ADD 纹理环境模式。
如果您使用的是 iOS,那么 Apple 的库可以为您预乘。查看示例 Texture2D 类并查找 kCGImageAlphaPremultipliedLast 标志。
如果您没有使用支持预乘的图像加载器,那么您必须在加载图像后手动执行此操作。伪代码:
uint8* LoadRGBAImage(const char* pImageFileName) {
Image* pImage = LoadImageData(pImageFileName);
if (pImage->eFormat != FORMAT_RGBA)
return NULL;
// allocate a buffer to store the pre-multiply result
// NOTE that in a real scenario you'll want to pad pDstData to a power-of-2
uint8* pDstData = (uint8*)malloc(pImage->rows * pImage->cols * 4);
uint8* pSrcData = pImage->pBitmapBytes;
uint32 bytesPerRow = pImage->cols * 4;
for (uint32 y = 0; y < pImage->rows; ++y) {
byte* pSrc = pSrcData + y * bytesPerRow;
byte* pDst = pDstData + y * bytesPerRow;
for (uint32 x = 0; x < pImage->cols; ++x) {
// modulate src rgb channels with alpha channel
// store result in dst rgb channels
uint8 srcAlpha = pSrc[3];
*pDst++ = Modulate(*pSrc++, srcAlpha);
*pDst++ = Modulate(*pSrc++, srcAlpha);
*pDst++ = Modulate(*pSrc++, srcAlpha);
// copy src alpha channel directly to dst alpha channel
*pDst++ = *pSrc++;
}
}
// don't forget to free() the pointer!
return pDstData;
}
uint8 Modulate(uint8 u, uint8 uControl) {
// fixed-point multiply the value u with uControl and return the result
return ((uint16)u * ((uint16)uControl + 1)) >> 8;
}
就个人而言,我正在使用 libpng 并手动进行预乘。
无论如何,在预乘之后,只需将字节数据绑定为 RGBA OpenGL 纹理即可。使用 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);之后你只需要一个纹理单元就可以了。您应该完全(或非常接近)您想要的。您可能必须使用 glBlendFunc(GL_SRC_ALPHA, GL_ONE);顺便说一句,如果你真的想让它看起来有光泽。
这与 Ozirus 方法略有不同。他从不通过预乘来“减少”纹理的 RGB 值,因此 RGB 通道被添加太多,看起来有点褪色/过亮。
我认为 premultiply 方法更类似于 Overlay,而 Ozirus 方法是 Soft Light。
更多信息,请参见:
http://en.wikipedia.org/wiki/Alpha_compositing
搜索“预乘 alpha”