2010-12-05 5 views
5

J'ai des particules que je veux pouvoir changer la couleur du code, donc n'importe quelle couleur peut être utilisée. Donc, j'ai seulement une texture qui a fondamentalement la luminance. J'ai appliqué glColor4f(1f, 0f, 0f, 1f); pour appliquer la couleur.OpenGL ES 1.1: Comment changer la couleur de la texture sans perdre de luminance?

Chaque blendfunc que j'ai essayé et qui est proche du travail se termine comme la dernière image ci-dessous. Je veux toujours préserver la luminance, comme dans l'image du milieu. (Cela ressemble aux filtres Superposition ou Lumière tamisée dans Photoshop, si la couche de couleur était au-dessus de la couche de texture.)

Des idées pour ce faire sans shaders programmables? Aussi, puisque ce sont des particules, je ne veux pas de boîte noire derrière, je veux que ça s'ajoute à la scène.

alt text

+0

Je ne crois pas qu'il soit possible avec pipeline fixe, vous aurez besoin d'un fragment shader pour y parvenir. – ognian

Répondre

9

Voici une solution qui pourrait être proche de ce que vous cherchez:

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); 

Ce qu'il fait est de multiplier la texture originale par la couleur spécifiée et ajoute ensuite les valeurs de pixels de la texture originale sur:

final_color.rgba = original_color.rgba * color.rgba + original_color.rgba; 

Cela se traduira par une image plus claire que ce que vous avez demandé, mais peut-être assez bon avec quelques t weaking. Si vous souhaitez conserver la valeur alpha de la texture, vous devez utiliser GL_COMBINE au lieu de GL_ADD (+ définir correctement GL_COMBINE_RGB et GL_COMBINE_ALPHA).

Voici quelques résultats en utilisant cette technique sur votre texture. alt text

+0

BTW, ne pas oublier de définir le pointeur de coordonnées de texture pour l'unité de texture 1: glClientActiveTexture (GL_TEXTURE1); glEnableClientState (GL_TEXTURE_COORD_ARRAY); glTexCoordPointer (2, GL_SHORT, 0, spriteTexcoords); – Ozirus

+0

Merci! Cela semble bon. Malheureusement, j'ai trouvé en essayant cela sur Android, que Android ne supporte que partiellement 1.1, et multi-texturing est sorti. Mais il semble que ce soit la seule façon de le faire. – Tenfour04

2

NONSENSE! Vous n'avez pas besoin d'utiliser la multi-texturation. Juste prémultiply votre alpha.

Si vous précultez alpha sur l'image après l'avoir chargé et avant de créer la texture GL, alors vous n'avez besoin que d'une unité de texture pour le mode d'environnement de texture GL_ADD.

Si vous êtes sur iOS alors les bibliothèques d'Apple peuvent premultiply pour vous. Voir l'exemple de la classe Texture2D et recherchez l'indicateur kCGImageAlphaPremultipliedLast.

Si vous n'utilisez pas un chargeur d'images prenant en charge prémultiplié, vous devez le faire manuellement après avoir chargé l'image. Code Pseudo:

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; 
} 

Personnellement, j'utilise libpng et manuellement prémultiplication. Quoi qu'il en soit, après la prémultiplication, il suffit de lier les données de l'octet comme une texture OpenGL RGBA. En utilisant glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); avec une seule unité de texture devrait être tout ce dont vous avez besoin après cela. Vous devriez obtenir exactement (ou tout près) ce que vous voulez. Vous devrez peut-être utiliser glBlendFunc (GL_SRC_ALPHA, GL_ONE); aussi bien si vous voulez vraiment rendre la chose brillante btw.

Ceci est subtilement différent de la méthode Ozirus. Il ne "réduit" jamais les valeurs RVB de la texture en prémultipliant, donc les canaux RVB sont trop rajoutés et ont l'air un peu délavés/trop lumineux.Je suppose que la méthode premultiply est plus proche de Overlay alors que la méthode Ozirus est Soft Light.

Pour en savoir plus, voir:

http://en.wikipedia.org/wiki/Alpha_compositing

Chercher "prémultipliée alpha"

Questions connexes