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,而多重纹理已经过时了。但看起来这是唯一可行的方法。