cubemap - opengl-mezcla con contenidos anteriores de framebuffer
cubemap opengl (3)
Borre el FBO con negro transparente (0, 0, 0, 0), dibuje hacia atrás con el frente
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
y dibujar el FBO con
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
para obtener el resultado exacto.
Como escribió Ben Supnik, el FBO contiene color ya multiplicado con el canal alfa, así que en lugar de hacerlo nuevamente con GL_SRC_ALPHA, se dibuja con GL_ONE. El color de destino se atenúa normalmente con GL_ONE_MINUS_SRC_ALPHA.
La razón para mezclar el canal alfa en el búfer de esta manera es diferente:
La fórmula para combinar transparencia es
resultTr = sTr * dTr
(Utilizo syd debido al paralelo con el origen y el destino de OpenGL, pero como puede ver, el orden no importa).
Escrito con opacidades (valores alfa) esto se convierte en
1 - rA = (1 - sA) * (1 - dA)
<=> rA = 1 - (1 - sA) * (1 - dA)
= 1 - 1 + sA + dA - sA * dA
= sA + (1 - sA) * dA
que es la misma que la función de mezcla (factores de origen y destino) (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) con la ecuación de mezcla predeterminada GL_FUNC_ADD .
Como un aparte:
Lo anterior responde al problema específico de la pregunta, pero si puede elegir fácilmente el orden de dibujo, en teoría podría ser mejor dibujar un color premultiplied en el búfer de adelante hacia atrás con
glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
y de otro modo usar el mismo método.
Mi razonamiento detrás de esto es que la tarjeta gráfica puede omitir la ejecución del sombreador para regiones que ya son sólidas. No he probado esto, sin embargo, por lo que puede no hacer ninguna diferencia en la práctica.
Estoy representando una textura a través de un objeto de marco de marco, y cuando dibujo primitivas transparentes, las primitivas se combinan correctamente con otras primitivas dibujadas en ese único paso de dibujo, pero no se combinan correctamente con el contenido anterior del framebuffer.
¿Hay alguna manera de mezclar correctamente los contenidos de la textura con los nuevos datos que llegan?
EDITAR: Más información requerida, intentaré explicar más claramente;
El modo de mezcla que estoy usando es GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA. (Creo que es típicamente el modo de mezcla estándar)
Estoy creando una aplicación que rastrea el movimiento del mouse. Dibuja líneas que conectan la posición anterior del mouse con la posición actual del mouse, y como no quiero volver a dibujar las líneas en cada cuadro, pensé que dibujaría una textura, nunca borraría la textura y luego simplemente dibujaría un rectángulo con eso. textura en él para mostrarlo.
Todo esto funciona bien, excepto que cuando dibujo formas con alfa menos de 1 en la textura, no se mezcla correctamente con el contenido anterior de la textura. Digamos que tengo algunas líneas negras con alfa = .6 dibujadas en la textura. Un par de ciclos de dibujo más tarde, luego dibujo un círculo negro con alfa = .4 sobre esas líneas. Las líneas "debajo" del círculo están completamente sobrescritas. Aunque el círculo no es negro plano (se combina correctamente con el fondo blanco), no hay "líneas más oscuras" debajo del círculo como cabría esperar.
Sin embargo, si dibujo las líneas y el círculo en el mismo marco, se mezclan correctamente. Mi conjetura es que la textura simplemente no se mezcla con su contenido anterior. Es como si solo se mezclara con el glclearcolor. (Que, en este caso es <1.0f, 1.0f, 1.0f, 1.0f>)
Como dijo Ben Supnik, la mejor manera de hacerlo es renderizar toda la escena con funciones de mezcla separadas para color y alfa. Si está utilizando la función clásica de mezcla no premultiplicada, intente glBlendFuncSeparateOES (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE) para renderizar su escena a FBO. y glBlendFuncSeparateOES (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) para renderizar el FBO a la pantalla.
No es 100% preciso, pero en la mayoría de los casos eso no creará una transparencia inesperada.
Tenga en cuenta que el hardware antiguo y algunos dispositivos móviles (en su mayoría dispositivos OpenGL ES 1.x, como el iPhone original y 3G) no admiten funciones de mezcla separadas. :(
Creo que hay dos posibles problemas aquí.
Recuerde que todas las líneas de superposición se mezclan dos veces aquí. Una vez cuando se mezclan con la textura FBO, y otra vez cuando la textura FBO se mezcla sobre la escena.
Entonces, la primera posibilidad es que no tenga habilitada la mezcla cuando dibuje una línea sobre otra en la superposición de FBO. Cuando dibuja en una superficie RGBA con la fusión desactivada, el alfa actual simplemente se escribe directamente en el canal alfa de la superposición de FBO. Luego, más tarde, cuando mezcla toda la textura FBO sobre la escena, ese alfa hace que sus líneas sean translúcidas. Por lo tanto, si tiene mezclas contra "el mundo" pero no entre elementos superpuestos, es posible que no se produzca ninguna fusión.
Otro problema relacionado: cuando se mezcla una línea sobre otra en el modo de mezcla "estándar" (src alpha, 1 - src alpha) en el FBO, el canal alfa de la parte "blended" contendrá una mezcla de las alfas del Dos elementos superpuestos. Esto probablemente no es lo que quieres.
Por ejemplo, si dibuja dos líneas alfa del 50% una sobre la otra en la superposición, para obtener el efecto equivalente cuando blitea la FBO, necesita que la alfa de la FBO sea ... 75%. (Es decir, 1 - (1-.5) * (1-0.5), que es lo que sucedería si solo dibujara dos líneas alfa del 50% sobre su escena. Pero cuando dibuje las dos líneas del 50%, obtén un 50% de alfa en el FBO (una mezcla del 50% con ... 50%.
Esto plantea el problema final: al mezclar previamente las líneas entre sí antes de mezclarlas en el mundo, está cambiando el orden de dibujo. Mientras que podría haber tenido:
mezcla (mezcla (mezcla (color de fondo, modelo), primera línea), segunda línea);
ahora tendrás
mezcla (mezcla (primera línea, segunda línea), mezcla (color de fondo, modelo)).
En otras palabras, la premezcla de las líneas de superposición en un FBO cambia el orden de fusión y, por lo tanto, cambia el aspecto final de una manera que quizás no desee.
Primero, la forma simple de evitar esto: no use un FBO. Me doy cuenta de que esto es un tipo de respuesta de "rediseñe su aplicación", pero usar un FBO no es lo más barato, y las tarjetas GL modernas son muy buenas para dibujar líneas. Entonces, una opción sería: en lugar de combinar líneas en un FBO, escriba la geometría de la línea en un objeto de búfer de vértice (VBO). Simplemente extienda el VBO un poco cada vez. Si está dibujando menos de, digamos, 40,000 líneas a la vez, esto seguramente será tan rápido como lo estaba haciendo antes.
(Una sugerencia si sigue esta ruta: use glBufferSubData para escribir las líneas, no glMapBuffer; la asignación puede ser costosa y no funciona en sub-rangos en muchos controladores ... mejor para que el controlador copie los pocos vértices nuevos .)
Si esa no es una opción (por ejemplo, si dibuja una combinación de tipos de formas o utiliza una combinación de estado GL, de tal manera que "recordar" lo que hizo es mucho más complejo que simplemente acumular vértices), es posible que desee cambia cómo dibujas en el VBO.
Básicamente, lo que debe hacer es habilitar la mezcla por separado; inicialice la superposición a negro + 0% alfa (0,0,0,0) y mezcle "mezclando de manera estándar" el RGB pero combinando de forma aditiva los canales alfa. Esto todavía no es del todo correcto para el canal alfa, pero en general está mucho más cerca. Sin esto, las áreas sobre dibujadas serán demasiado transparentes.
Luego, al dibujar el FBO, use alfa "pre-multiplicada", es decir, (uno, uno-menos-src-alph).
Aquí es por qué se necesita ese último paso: cuando dibuja en el FBO, ya ha multiplicado cada llamada de sorteo por su canal alfa (si la fusión está activada). Como está dibujando sobre negro, una línea verde (0,1,0,0.5) ahora es verde oscura (0,0.5,0,0.5). Si alfa está activado y vuelve a mezclarse normalmente, se vuelve a aplicar el alfa y tendrá 0.0.25,0,0.5.). Simplemente utilizando el color FBO tal como está, evitas la segunda multiplicación alfa.
Esto a veces se llama alfa "pre-multiplicado" porque el alfa ya se ha multiplicado en el color RGB. En este caso, desea que obtenga resultados correctos, pero en otros casos, los programadores lo utilizan para la velocidad. (Al pre-multiplicar, elimina un mult por píxel cuando se realiza la operación de mezcla).
¡Espero que ayude! Mezclar correctamente cuando las capas no se mezclan en orden se vuelve realmente complicado, y la mezcla separada no está disponible en el hardware antiguo, por lo que simplemente dibujar las líneas cada vez puede ser el camino de la menor miseria.