Estoy trabajando en un juego similar a Megaman donde necesito cambiar el color de ciertos píxeles en tiempo de ejecución. Como referencia : en Megaman cuando cambias tu arma seleccionada, la paleta del personaje principal cambia para reflejar el arma seleccionada. No todos los colores del sprite cambian, solo algunos cambian .
Este tipo de efecto era común y bastante fácil de hacer en el NES ya que el programador tenía acceso a la paleta y al mapeo lógico entre píxeles e índices de paleta. Sin embargo, en el hardware moderno, esto es un poco más desafiante porque el concepto de paletas no es el mismo.
Todas mis texturas son de 32 bits y no usan paletas.
Hay dos maneras que conozco para lograr el efecto que quiero, pero tengo curiosidad por saber si hay mejores maneras de lograr este efecto fácilmente. Las dos opciones que conozco son:
- Use un sombreador y escriba GLSL para realizar el comportamiento de "intercambio de paleta".
- Si los sombreadores no están disponibles (por ejemplo, porque la tarjeta gráfica no los admite), entonces es posible clonar las texturas "originales" y generar diferentes versiones con los cambios de color aplicados previamente.
Idealmente, me gustaría usar un sombreador, ya que parece sencillo y requiere poco trabajo adicional en oposición al método de textura duplicada. Me preocupa que duplicar texturas solo para cambiar un color en ellas está desperdiciando VRAM, ¿no debería preocuparme por eso?
Editar : Terminé usando la técnica de respuesta aceptada y aquí está mi sombreador para referencia.
uniform sampler2D texture;
uniform sampler2D colorTable;
uniform float paletteIndex;
void main()
{
vec2 pos = gl_TexCoord[0].xy;
vec4 color = texture2D(texture, pos);
vec2 index = vec2(color.r + paletteIndex, 0);
vec4 indexedColor = texture2D(colorTable, index);
gl_FragColor = indexedColor;
}
Ambas texturas son de 32 bits, una textura se usa como tabla de búsqueda que contiene varias paletas que son todas del mismo tamaño (en mi caso, 6 colores). Utilizo el canal rojo del píxel de origen como índice de la tabla de colores. ¡Esto funcionó a las mil maravillas para lograr el intercambio de paletas como Megaman!
Hay 2 formas en que puedo pensar en hacer esto.
Camino # 1: GL_MODULATE
Puede hacer el sprite en tonos de gris y
GL_MODULATE
la textura cuando se dibuja con un solo color sólido.Por ejemplo,
Sin embargo, esto no le permite mucha flexibilidad, básicamente solo puede ir más claro y más oscuro del mismo tono.
Camino # 2:
if
declaración (malo para el rendimiento)Otra cosa que podría hacer es colorear sus texturas con algunos valores clave que involucran R, G y B. SO, por ejemplo, el primer color es (1,0,0), el segundo color es (0,1,0), el tercero el color es (0,0,1).
Declaras un par de uniformes como
Luego, en el sombreador, el color de píxel final es algo así como
color1
,color2
,color3
, Son uniformes por lo que se pueden establecer antes de las carreras de sombreado (dependiendo de lo que Megaman "traje" está en), entonces el shader simplemente hace el resto.También podría usar
if
declaraciones si necesitara más colores, pero tendría que hacer que las comprobaciones de igualdad funcionen correctamente (las texturas generalmente estánR8G8B8
entre 0 y 255 en el archivo de textura, pero en el sombreador, tiene flotantes rgba)Forma # 3: simplemente almacena de forma redundante las diferentes imágenes de colores en el mapa de sprites
Esta puede ser la forma más fácil, si no estás tratando de conservar la memoria
fuente
Yo usaría sombreadores. Si no quiere usarlos (o no puede), iría con una textura (o parte de una textura) por color y usaría solo blanco limpio. Esto le permitirá teñir la textura (por ejemplo, a través
glColor()
) sin tener que preocuparse por crear texturas adicionales para los colores. Incluso puede intercambiar colores en la ejecución sin trabajo de textura adicional.fuente
"No todos los colores del sprite cambian, solo algunos cambian".
Los viejos juegos hacían trucos de paleta porque eso era todo lo que tenían. En estos días, puede usar múltiples texturas y combinarlas de varias maneras.
Puede crear una textura de máscara de escala de grises separada que use para decidir qué píxeles cambiarán de color. Las áreas blancas en la textura reciben la modificación a todo color, y las áreas negras permanecen sin cambios.
En el idioma del sombreador:
O puede usar texturizado de función fija con varios modos de combinación de texturas.
Obviamente, hay muchas maneras diferentes de hacerlo; puede poner máscaras para diferentes colores en cada uno de los canales RGB, o modular los colores cambiando el tono en un espacio de color HSV.
Otra opción, quizás más simple, es simplemente dibujar el sprite usando una textura separada para cada componente. Una textura para el cabello, una para la armadura, una para las botas, etc. Cada color se puede colorear por separado.
fuente
En primer lugar, generalmente se conoce como ciclismo (ciclado de paletas), por lo que podría ayudar a su Google-fu.
Esto dependerá exactamente de los efectos que desee producir y si se trata de contenido 2D estático o material 3D dinámico (es decir, si solo desea lidiar con spites / texturas, o renderizar una escena 3D completa y luego cambiar de paleta). Además, si se limita a una serie de colores o utiliza todo color.
Un enfoque más completo, usando sombreadores, sería producir imágenes indexadas en color con una textura de paleta. Haga una textura, pero en lugar de tener colores, tenga un color que represente un índice para buscar y luego tenga otra textura de colores que sea la placa. Por ejemplo, el rojo podría ser la coordenada t de las texturas y el verde podría ser la coordenada s. Use un sombreador para hacer la búsqueda. Y animar / modificar los colores de esa textura de paleta. Esto estaría bastante cerca del efecto retro, pero solo funcionaría para contenido 2D estático como sprites o texturas. Si está haciendo gráficos retro genuinos, es posible que pueda producir sprites de color indexados reales y escribir algo para importarlos y las paletas.
También querrá hacer ejercicio si va a utilizar una paleta 'global'. Al igual que la antigüedad del hardware, menos memoria para las paletas, ya que solo necesita una, pero es más difícil producir su obra de arte, ya que tiene que sincronizar la paleta en todas las imágenes) o dar a cada imagen su propia paleta. Eso le daría más flexibilidad pero usaría más memoria. Por supuesto, puedes hacer ambas cosas, también puedes usar paletas para las cosas en las que cambias de color. También descubra en qué medida desea limitar sus colores, los juegos antiguos usarían 256 colores, por ejemplo. Si está utilizando una textura, obtendrá el número de píxeles, por lo que un 256 * 256 le dará
Si solo desea un efecto falso barato, como el flujo de agua, puede crear una segunda textura que contenga una máscara de escala de grises en el área que desea modificar, luego use las texturas enmascaradas para modificar el tono / saturación / brillo por la cantidad en el Textura de máscara de escala de grises. Podría ser aún más vago y simplemente cambiar el tono / brillo / saturación de cualquier cosa en un rango de color.
Si lo necesitara en 3D completo, podría intentar generar la imagen indexada sobre la marcha, pero sería lento ya que tendría que buscar el palet, también es probable que tenga una gama limitada de colores.
De lo contrario, podría simularlo en el sombreador, si color == intercambiando color, cámbielo. Eso sería lento y solo funcionaría con un número limitado de intercambio de colores, pero no debería estresar a ninguno de los equipos actuales, especialmente si solo se trata de gráficos 2D y siempre puede marcar qué sprites tienen intercambio de color y usar un sombreador diferente.
De lo contrario, fingirlos realmente, hacer un montón de texturas animadas para cada estado.
Aquí hay una gran demostración del ciclo de pallets realizado en HTML5 .
fuente
Creo que si son lo suficientemente rápidos para que el espacio de color [0 ... 1] se divida en dos:
De esta manera, los valores de color entre 0 y 0.5 se reservan para valores de color normales; y 0.5 - 1.0 están reservados para valores "modulados", donde 0.5..1.0 se asigna a cualquier rango seleccionado por el usuario.
Solo la resolución de color se trunca de 256 valores por píxel a 128 valores.
Probablemente uno puede usar funciones incorporadas como max (color-0.5f, 0.0f) para eliminar completamente los ifs (intercambiándolos por multiplicaciones por cero o uno ...).
fuente