2010-12-05 15 views
5

Tengo partículas que deseo que puedan cambiar el color del código, por lo que se puede usar cualquier color. Entonces tengo una sola textura que básicamente tiene luminancia.OpenGL ES 1.1: ¿Cómo cambiar el color de la textura sin perder la luminancia?

He estado usando glColor4f(1f, 0f, 0f, 1f); para aplicar el color.

Cada blendfunc que he probado que ha estado a punto de funcionar termina como la última imagen a continuación. Todavía quiero preservar la luminancia, como en la imagen del medio. (Esto es como los filtros Superposición o Luz suave en Photoshop, si la capa de color estaba en la parte superior de la capa de textura.)

¿Alguna idea de cómo hacer esto sin sombreadores programables? Además, dado que estas son partículas, no quiero una caja negra detrás, quiero que se agregue a la escena.

alt text

+0

no creo que es posible con la tubería fija, tendrá un fragment shader para lograrlo. – ognian

Respuesta

9

Aquí es una solución que podría estar cerca de lo que usted está buscando:

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

lo que hace es multiplicar la textura original por el color especificado y luego suma los valores de píxeles de la textura original en la parte superior:

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

Esto dará como resultado una imagen más brillante de lo que lo solicitado pero podría ser lo suficientemente bueno con un poco de t debilitamiento.

Si desea conservar el valor alfa de la textura, deberá usar GL_COMBINE en lugar de GL_ADD (+ establecer GL_COMBINE_RGB y GL_COMBINE_ALPHA correctamente).

Aquí hay algunos resultados que utilizan esta técnica en su textura. alt text

+0

Por cierto, no se olvide de establecer las coordenadas de textura para el puntero de unidad de textura 1: glClientActiveTexture (GL_TEXTURE1); glEnableClientState (GL_TEXTURE_COORD_ARRAY); glTexCoordPointer (2, GL_SHORT, 0, spriteTexcoords); – Ozirus

+0

Gracias! Esto luce bien. Lamentablemente, me encontré al probar esto en Android, que Android solo es compatible parcialmente con 1.1, y que la texturización múltiple ya no existe. Pero parece que esta es la única forma en que podría hacerse. – Tenfour04

2

NONSENSE! No tiene que usar multi texturas. Solo premultiply tu alfa.

Si premultiplica alfa en la imagen después de cargarla y antes de crear la textura GL para ella, solo necesita una unidad de textura para el modo env de textura GL_ADD.

Si está en iOS, las librerías de Apple pueden premultiplicarse para usted. Vea el ejemplo de la clase Texture2D y busque el indicador kCGImageAlphaPremultipliedLast.

Si no está utilizando un cargador de imágenes que admite premultiplicar, debe hacerlo manualmente después de cargar la imagen. Pseudocódigo:

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

Personalmente, estoy usando libpng y premultiplicando manualmente.

De todos modos, después de ti premultiply, simplemente une los datos de bytes como una textura RGBA OpenGL. Usando glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); con una sola unidad de textura debería ser todo lo que necesitas después de eso. Deberías obtener exactamente (o muy cerca) lo que quieres. Puede que tenga que usar glBlendFunc (GL_SRC_ALPHA, GL_ONE); también si realmente quieres que la cosa luzca brillante por cierto.

Esto es sutilmente diferente del método de Ozirus. Nunca está "reduciendo" los valores RGB de la textura mediante premultiplicación, por lo que los canales RGB se agregan demasiado y se ven como desvaídos/demasiado brillantes.

supongo que el método premultiplicar es más parecido a Overlay mientras que el método es Ozirus luz suave.

Para más información, véase:

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

Búsqueda de "alfa premultiplicado"

Cuestiones relacionadas