Iphone OpenGL ES 1.1:如何在不损失亮度的情况下更改纹理颜色?
我有一些粒子,我希望能够在代码中改变它们的颜色,所以任何颜色都可以使用。所以我只有一个基本上有亮度的纹理 我一直在使用Iphone OpenGL ES 1.1:如何在不损失亮度的情况下更改纹理颜色?,iphone,android,opengl-es,Iphone,Android,Opengl Es,我有一些粒子,我希望能够在代码中改变它们的颜色,所以任何颜色都可以使用。所以我只有一个基本上有亮度的纹理 我一直在使用glColor4f(1f,0f,0f,1f)以应用颜色 我试过的每一款blendfunc都接近正常工作,结果都像下面的最后一张图片。我仍然想保持亮度,就像中间图片一样。(这类似于Photoshop中的叠加或软光过滤器,如果颜色层位于纹理层的顶部。) 如何在没有可编程着色器的情况下实现这一点?此外,由于这些是粒子,我不希望在其后面有一个黑匣子,我希望它添加到场景中 这里有一个解决方
glColor4f(1f,0f,0f,1f)代码>以应用颜色
我试过的每一款blendfunc都接近正常工作,结果都像下面的最后一张图片。我仍然想保持亮度,就像中间图片一样。(这类似于Photoshop中的叠加或软光过滤器,如果颜色层位于纹理层的顶部。)
如何在没有可编程着色器的情况下实现这一点?此外,由于这些是粒子,我不希望在其后面有一个黑匣子,我希望它添加到场景中
这里有一个解决方案,可能与您想要的非常接近:
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glActiveTexture( GL_TEXTURE0 );
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, spriteTexture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
glActiveTexture( GL_TEXTURE1 );
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, spriteTexture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
它所做的是将原始纹理乘以指定的颜色,然后在顶部添加原始纹理的像素值:
final_color.rgba = original_color.rgba * color.rgba + original_color.rgba;
这将导致一个比你所要求的更明亮的图像,但通过一些调整可能已经足够好了
如果要保留纹理的alpha值,则需要使用GL_COMBINE而不是GL_ADD(+正确设置GL_COMBINE_RGB和GL_COMBINE_alpha)
下面是在纹理上使用此技术的一些结果。
胡说八道!你不必使用多重纹理。只需预先乘以你的阿尔法
如果在加载图像后和为其创建GL纹理之前对其预乘alpha,则GL_添加纹理环境模式只需要一个纹理单元
如果您使用的是iOS,那么苹果的LIB可以为您提供预乘功能。请参阅示例Texture2D类并查找KCGIMAGEAlphaPremultipledLast标志
如果您没有使用支持预乘的图像加载程序,则必须在加载图像后手动执行此操作。伪代码:
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;
}
uint8*LoadRGBAImage(const char*pImageFileName){
Image*pImage=LoadImageData(pImageFileName);
如果(pImage->eFormat!=格式\u RGBA)
返回NULL;
//分配一个缓冲区来存储预乘法结果
//请注意,在实际场景中,您需要将pDstData填充到2次幂
uint8*pDstData=(uint8*)malloc(pImage->rows*pImage->cols*4);
uint8*pSrcData=pImage->pBitmapBytes;
uint32 bytesPerRow=pImage->cols*4;
对于(uint32 y=0;yrows;++y){
字节*pSrc=pSrcData+y*bytesPerRow;
字节*pDst=pDstData+y*bytesPerRow;
对于(uint32 x=0;xcols;++x){
//使用alpha通道调制src rgb通道
//将结果存储在dst rgb通道中
uint8 srcAlpha=pSrc[3];
*pDst++=调制(*pSrc++,srcAlpha);
*pDst++=调制(*pSrc++,srcAlpha);
*pDst++=调制(*pSrc++,srcAlpha);
//将src alpha通道直接复制到dst alpha通道
*pDst++=*pSrc++;
}
}
//别忘了释放()指针!
返回pDstData;
}
uint8调制(uint8 u,uint8 u控制){
//定点将u值与uControl相乘并返回结果
返回((uint16)u*((uint16)uControl+1))>>8;
}
就我个人而言,我正在手动使用libpng和预乘
无论如何,在预乘之后,只需将字节数据绑定为RGBA OpenGL纹理。使用glTexEnvi(GL_纹理环境、GL_纹理环境模式、GL_添加);在那之后,你只需要一个纹理单元。你应该得到你想要的东西。您可能必须使用glBlendFunc(GL_SRC_ALPHA,GL_ONE);顺便说一句,如果你真的想让这个东西看起来闪闪发光的话
这与Ozirus方法有细微的不同。他从不通过预乘来“减少”纹理的RGB值,因此RGB通道添加得太多,看起来有点褪色/太亮
我认为预乘法更类似于叠加法,而Ozirus法是柔和的光线
有关更多信息,请参阅:
搜索“预乘alpha”我不相信使用固定管道是可能的,你需要一个片段着色器来实现它。顺便说一句,别忘了为纹理单元1设置纹理坐标指针:glClientActiveTexture(GL_TEXTURE1);glEnableClientState(GL_纹理_坐标_阵列);glTexCoordPointer(2,GL_SHORT,0,spritedexcoords);谢谢这看起来不错。不幸的是,我在Android上试用时发现,Android只部分支持1.1,而多重纹理已经过时了。但看起来这是唯一可行的方法。