Mezcla alfa retardada

En este artículo quiero hablar sobre los métodos para mezclar geometría rasterizada. Los modelos de mezcla clásicos de objetos translúcidos - Alfa, Aditivo, Multiplicativo - están unidos por el mismo principio de dibujo: dibuja secuencialmente una primitiva tras otra, mezclando los píxeles recibidos en la salida del sombreador de fragmentos con lo que está en el búfer actual. Cada nueva primitiva actualiza el área del búfer en el que se dibuja; en el caso de la combinación alfa, los objetos que están más arriba mejoran los dibujados previamente. Pero, ¿qué pasa si quieres hacer algo con un grupo de objetos dibujados en la parte superior de la escena, por ejemplo, recortarlos por máscara o resaltarlos? Aquí se me ocurren dos decisiones: hacer cambios en su material (es decir, cambiar el sombreador, expandir el conjunto de texturas), por ejemplo, agregar una proyección de otra textura,que será responsable de la máscara de transparencia. Sin embargo, si tenemos muchos objetos moteados, cambiar cada material único es inconveniente y está lleno de errores. La segunda opción es dibujar todos los objetos que nos interesan en un objetivo separado de pantalla completa y dibujarlo ya en la escena final. Aquí podemos hacer lo que queramos con su contenido, pero esto requiere la asignación de memoria adicional y, lo más desagradable, cambiar el renderizado de destino. Esta no es la operación "más barata" en dispositivos móviles, que deberá realizarse dos veces. ¿Y si quieres trabajar con varias capas como esta?Aquí podemos hacer lo que queramos con su contenido, pero esto requiere la asignación de memoria adicional y, lo más desagradable, cambiar el renderizado de destino. Esta no es la operación "más barata" en dispositivos móviles, que deberá realizarse dos veces. ¿Y si quieres trabajar con varias capas como esta?Aquí podemos hacer lo que queramos con su contenido, pero esto requiere la asignación de memoria adicional y, lo más desagradable, cambiar el renderizado de destino. Esta no es la operación "más barata" en dispositivos móviles, que deberá realizarse dos veces. ¿Y si quieres trabajar con varias capas como esta?



Hay otra forma más simple y elegante de resolver estos problemas. ¡Podemos pintar la escena al revés!

Una pequeña digresión para recordarle cómo funciona el método de representación clásico
- Alpha Blending , , , . 4 RGBA, RGB — A(Alpha) — ( ). . :


ColorSrc — RGB , ( , ), ColorDst — , , Color_Result — , , , . Variable1 Variable2, ? , ( , ). , : , ... 

:


AlphaSrc — - (), OneMinusAlphaSrc, , 1.0 — AlphaSrc. : 1 * + 2 * (1 — ). alpha (). = 1, , = 0, . OpenGL .

OpenGL ES 2.0 — .

Cómo se forma la imagen en pasos: primero dibujamos un fondo, luego dibujamos todos los objetos en capas, uno tras otro. Lo que se representa por última vez sobrescribe los píxeles anteriores: 





Cual es el truco 


La esencia de la tecnología de renderizado inverso o, como también se le puede llamar, mezcla retardada es la siguiente. Dibujamos la escena hacia atrás usando una fórmula de fusión diferente. Además, la imagen final seguirá siendo exactamente la misma que con el enfoque clásico.

¿Cómo funciona?


El método de mezclar a través del canal de transparencia de la imagen que dibujamos se describió anteriormente. Ahora lo cambiaremos al revés: utilizaremos la transparencia de los píxeles ya dibujados (o más bien, mezclando la transparencia dibujada con la ya dibujada). Es decir, en lugar de AlphaSrc usaremos AlphaSaturate, y en lugar de OneMinusAlphaSrc - One. Resulta que si ya hay algo con transparencia = 1 en el búfer, la contribución será cero y el color de dicho píxel no cambiará. Si no había transparencia, agreguemos ambos colores juntos (para esto necesitaremos borrar el búfer del marco con ceros o negro con cero transparencia). Con esta adición, el color resultante será igual al dibujado. La fórmula final se ve así:
 

(aprox. AlphaSaturate = min (AlphaSrc, 1 - AlphaDst))

Es necesario agregar los valores de transparencia: debe acumularse capa por capa, es decir, tendremos Uno y Uno en las variables de mezcla para el canal alfa. ¿Por qué no modificamos ColorDst y limpiamos el búfer con ceros? Esto es necesario para la mezcla de aditivos, AdditiveBlending solo diferirá en que tendrá cero en la variable AlphaSrc. No debe modificar la transparencia, solo el color.

Para mayor claridad, el esquema de representación inversa se ve así: 

Primero, borramos el búfer de cuadros. Luego establecemos la función de mezcla dada anteriormente y comenzamos a dibujar desde los objetos superiores (en el enfoque clásico, se dibujarían al final), bajando a los inferiores. La imagen de fondo se dibujará al final.


¿Cómo se puede usar esto?


Describiré varias tareas resueltas por este método, utilizando nuestro proyecto como ejemplo:

  1. Recorte de objetos por máscara con transparencia. Recorte suave de la sala de juegos:


    Después de dibujar el campo de juego, es suficiente para borrar la transparencia en esos lugares de la imagen que queremos ocultar. Esto se hace usando una fórmula de fusión, en la cual el objeto de máscara dibujado sobrescribe el color y la transparencia inversamente con su propia transparencia, y el grado de purificación puede ajustarse continuamente. En este caso, se utiliza la siguiente geometría para el recorte:


    Cambia de forma a medida que la cámara se mueve entre habitaciones. La fórmula de mezcla para la limpieza es la siguiente:

    ColorSrc = GL_ZERO,
    ColorDst = GL_ONE_MINUS_SRC_ALPHA,
    AlphaSrc = GL_ZERO,
    AlphaDst = GL_ONE_MINUS_SRC_ALPHA

    Puede usar cualquier geometría con cualquier textura, comenzando a limpiar desde la capa de la que necesitará:

  2. La desaparición suave del campo se realiza de manera similar. El precio de emisión es un DrawCall.
  3. :


    , UI, . , «» , , « », . , : , . :

    ColorSrc = GL_SRC_ALPHA,
    ColorDst = GL_ONE_MINUS_SRC_ALPHA,
    AlphaSrc = GL_ZERO,
    AlphaDst = GL_ONE
  4. , :


  5. «»:



    . , . — 2 DrawCalls.



Ambient occlusion





Hay un inconveniente, o más bien restricciones: no todas las mezclas pueden repetirse para tal técnica. La mezcla alfa y el aditivo son definitivamente posibles, pero debe adaptar o no usar sus propias mezclas especiales. Pero hay una salida: puede separar las etapas de renderizado de la escena. Parte de esto debe hacerse por el método inverso, parte es el habitual, y esto es lo que hicimos para obtener efectos especiales en la parte superior del campo y después del proceso.

Un punto importante con las técnicas de renderizado aditivo y mixto: si se dibuja ANTES del pasaje de renderizado inverso, y si no hay información de transparencia en la textura (textura como "punto blanco sobre fondo negro"), dicho objeto sobrescribirá la transparencia. En el pasaje de "retorno", se perderá información sobre esta sección, y visualmente se verá como un "cuadrado oscuro" o un borde negro alrededor de un punto aditivo ligero:


Esto se puede superar modificando la combinación de aditivos en términos de mezclar el canal alfa:

AlphaSrc = GL_ONE_MINUS_DST_ALPHA
AlphaDst = GL_ONE

Pero esto no es adecuado para todos los tipos de mezcla, y será más confiable modificar la textura en sí. Qué se entiende:

si hay texturas de la forma: 


Entonces necesitas hacer uno de ellos:


Es decir, el brillo de los canales de color debe convertirse en transparencia y estirar los colores inversamente con la transparencia. La textura resultante y antigua debería verse igual en un fondo negro. Manualmente, es poco probable que esto tenga éxito, tiene sentido hacer un convertidor automático. En este caso, el pseudocódigo de conversión de canal se verá así:

RGB_old = Texel_in.rgb
A_old = Texel_in.a
A_middle = 1.0 / ((RGB_old) / 3.0) * A_old // linear color space
RGB_new = RGB_old * A_middle;
A_shift = minimum( 1.0 / RGB_new.r, 1.0)
A_shift = minimum( 1.0 / RGB_new.g, A_shift)
A_shift = minimum( 1.0 / RGB_new.b, A_shift)
RGB_result = RGB_new * A_shift; 
A_result = (RGB_result) / 3.0)
Texel_out = Vector4(RGB_result, A_result)



Aquí voy a seguir los pasos para representar la escena de nuestro proyecto.
 
  1. . , -.

  2. , , , «» :


  3. UI:

  4. , , , :

  5. :

  6. :

  7. , .




Conclusión


El método permite trabajar de manera simple y económica con las capas de la escena que se dibujan, utilizando el canal alfa como máscara. Es relativamente sencillo implementarlo en un proyecto que ya funciona: no requiere una modificación profunda del código del subsistema de gráficos, es suficiente para cambiar el orden de representación y la fórmula de mezcla. En algunos lugares, puede ahorrar significativamente el rendimiento. Existen limitaciones, pero en la mayoría de los casos puede aceptarlas.

Source: https://habr.com/ru/post/undefined/


All Articles