¿Qué técnicas de renderizado usaría para dibujar un efecto de sombra paralela para las cartas en un juego de cartas?

13

¿Qué tipo de algoritmo de sombreado podría usarse para crear sombras como estas? ingrese la descripción de la imagen aquí

el que estoy haciendo es similar, pero todo se hace con una API de dibujo 2D impulsada por OpenGL, por lo que no hay una coordenada Z.

Además, para la mano en sí, realmente me gustaría tener una sensación de sombra como se ve aquí: ingrese la descripción de la imagen aquí

No estoy seguro de cómo lograr un aspecto sombreado cercano a eso.

El número de cartas está obligado a cambiar y las cartas se arrojan sobre la mesa, por lo que no puedo usar ningún tipo de mapa de luz.

¿Qué tipo de algoritmos debo analizar (aparte del desenfoque que sé que tendré que hacer?)

Gracias

Actualizar

Estoy haciendo un juego de cartas en 2D. Quiero agregar sombras paralelas a las cartas, un poco como:

ingrese la descripción de la imagen aquí

La forma en que pienso hacerlo es:

  • Mantenga una textura que sea del mismo tamaño que el backbuffer.
  • Dibuja rectángulos oscuros como tarjetas improvisadas para esa textura.

  • Desenfoca esa textura.

  • Dibuja mis cartas con esa textura.
  • Haga iluminación adicional en las tarjetas.
  • Dibuja esta textura en el backbuffer.

Mis preguntas son:

  • ¿Es esta la forma correcta de hacer esto?

  • ¿Hay alguna manera de hacerlo sin renderizar a la textura (manteniendo un mapa de bits
    tan grande como el backbuffer)?

  • ¿Es seguro asumir que el tamaño máximo de la textura no será
    excedido por el tamaño del backbuffer? (Lo que quiero decir es que si el backbuffer
    es 2000x3000, ¿es seguro decir que puedo crear una textura en
    la memoria de video de ese tamaño?

Gracias

jmasterx
fuente
1
Un punto estético en su segundo problema: eso no es realmente posible si realmente tiene esas cartas en la mano. Las cartas presionadas una al lado de la otra no se sombrean apreciablemente entre sí. No, a menos que tengas muchos de ellos. Realmente no puedes sostener las cartas de la forma en que se representan en esa imagen; esas tarjetas parecen estar separadas por varios milímetros; No son planos uno contra el otro. Simplemente no me preocuparía por eso.
Nicol Bolas

Respuestas:

18

Creo que todos están dando soluciones demasiado complicadas a este problema.

ingrese la descripción de la imagen aquí

Primero, tenemos la tarjeta (o lo que sea que quieras dibujar), representada aquí por (a). Luego, tomamos una copia, la rellenamos de negro y ejecutamos un desenfoque gaussiano (b). Todo esto sucede en Photoshop o cualquiera que sea tu herramienta de arte favorita.

A continuación, en el juego, cuando queremos dibujar la tarjeta, primero dibuje la imagen negra borrosa con mezcla multiplicativa (o alfa), desplace un poco en alguna dirección, y luego dibuje la tarjeta encima de eso. Voilá

Para obtener más trucos, puede alternar entre el sombreado y el renderizado de la tarjeta para obtener un efecto como (d), o primero dibujar todas las sombras y luego las cartas, como en (e) (coloreé las cartas en el caso (e) para mostrar que todavía estás separado =)

También es mejor no usar negro puro (o alfa completo) para que la sombra cree sombras más sutiles y transparentes.

Jari Komppa
fuente
2
+1 por eliminar las sombras del juego. También podría ir un paso más allá y modificar dónde se coloca la sombra si hay una luz en la escena.
FrenchyNZ
+1, bonita ilustración. Además, en el caso E, puede usar renderizar sombras oscuras en la mesa y semibrillo en tarjetas con plantilla. Eso será más complicado, pero el efecto será aún mejor :)
Kromster dice que apoya a Mónica el
2

El primero no es demasiado difícil. Si renderiza un canal alfa para su mano de tarjetas (que podría ser tan simple como negro para un píxel con una tarjeta en él y blanco para transparente), puede realizar cualquier tipo de desenfoque que desee solo en el canal alfa, y luego compensarlo y usarlo para controlar la iluminación de la mesa. (Presumiblemente, si no tiene un búfer Z, primero debería renderizar el canal alfa fuera de la pantalla, luego hacer la tabla con la máscara y luego renderizar las tarjetas reales).

El segundo se parece un poco a SSAO (oclusión ambiental del espacio de pantalla). Esa técnica requiere una coordenada Z. Sin embargo, si no tiene los ángulos variables entre las tarjetas (que es lo que supongo que no tiene Z-buffer), probablemente pueda hacer una aproximación bastante buena al representar una sombra paralela (como la primera) para cada tarjeta. Sin embargo, el rendimiento podría ser un poco complicado: cada avión necesitaría un canal alfa borroso para todos los planos que se encuentran sobre él, y si hay un montón de cartas en la mesa, eso podría ser un buen número de pases de renderizado.

John Calsbeek
fuente
SSAO es excesivo =) Es muy difícil saber qué técnica de sombreado se utiliza sin ver el ejemplo animado. Si las cartas siempre caen en ese orden y espaciadas una encima de la otra, sería más fácil simplemente pre-renderizar las sombras, pero nunca sabrías ver el juego en acción.
Patrick Hughes
0

¿No podrías hacer un mapa de sombras? Renderiza la escena a un fbo. Guarde solo los valores de profundidad y verifique el valor de profundidad normal en el sombreador para ver si se debe representar una sombra o no.

Joey Green
fuente
No estoy usando un Z Buffer, no hay 'profundidad'.
jmasterx
0

El siguiente proceso no requiere un objetivo de renderizado fuera de la pantalla. Sin embargo, al hacerlo, gana el requisito de que la tabla se dibuje primero . O al menos, no se dibuja nada en los píxeles que cubrirá la tabla antes de que se dibuje la tabla. También requiere que la tabla en sí sea una pieza única, no superpuesta: una imagen.

Además, su framebuffer necesita un componente alfa.

  1. Obtenga una imagen en escala de grises de una tarjeta. Hazlo borroso alrededor de los bordes, posiblemente expandiendo su tamaño. Esta es tu imagen de tarjeta de sombra. Tenga en cuenta que esta es una imagen de un solo canal. Cuando accede a esta textura en su sombreador, debe asegurarse de colocar el valor único en el componente alfa. Esto se puede hacer en su sombreador o en otro lugar.

    Un valor de 0.0 en la imagen significa que no hay sombra. Un valor de 1.0 en la imagen significa sombra total . Es decir, completamente negro. Probablemente desee un valor de 0.5 más o menos como su color más oscuro.

  2. Borre la pantalla de modo que el alfa esté configurado en cero .

  3. Antes de representar cualquier cosa (o al menos todo lo que se representará "debajo" de la tabla), para cada tarjeta, renderice la textura difusa, desplazada de la posición real de la tarjeta (pero con la misma orientación). La salida de color del sombreador debe ser La configuración de mezcla para esto debe ser (en lenguaje OpenGL):

    glBlendEquation(GL_MAX);

    Este modo de fusión se utiliza para evitar que las sombras superpuestas se vuelvan cada vez más oscuras o más claras. Simplemente toma el valor más oscuro escrito en ese píxel. Debería verse lo suficientemente bien.

    También debe usar la máscara de escritura de color para desactivar las escrituras de color.

  4. Renderiza la mesa. Al hacerlo, la combinación se debe configurar de la siguiente manera:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);

Si las restricciones son demasiado restrictivas para usted, entonces debe usar un objetivo de representación. Esto se hace de la siguiente manera:

  1. Crea la imagen de la tarjeta de sombra como antes.

  2. Primero, renderiza las sombras. Vincula el framebuffer de sombra (que solo necesita ser una imagen de un solo canal, si tu hardware puede renderizar a uno de esos). Borrar su valor a cero.

  3. Para cada tarjeta, renderice la imagen de la tarjeta de sombra, desplazada como antes. Su sombreador debe escribir el mismo valor en los cuatro componentes del color de salida. El modo de mezcla nuevamente debería ser glBlendEquation(GL_MAX).

  4. Regrese al framebuffer normal. Dibuja todo lo que quieras que se sombree.

  5. Ahora dibuje un quad de pantalla completa con la imagen de sombra que renderizamos. El sombreador debe almacenar el texel obtenido de la imagen en la sombra en el alfa de la salida; El RGB es irrelevante. El modo de mezcla debe ser:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
Nicol Bolas
fuente
En el primer método, creo que olvidó el paso 5: deshabilite la mezcla y renderice las tarjetas. Además, vale la pena señalar que el primer método no le permite obtener sombras entre tarjetas como se ve en la segunda captura de pantalla del OP.
Nathan Reed
@NathanReed: pensé que él sabía cómo apagar las cosas él mismo. Además, las "sombras entre cartas" no tienen ningún sentido, como señalé en mi comentario bajo la pregunta.
Nicol Bolas
1
Puede que no represente de manera realista cómo sostendrías las cartas, ¡pero se ve genial! Realmente no tiene "sentido" que las cartas floten sobre la mesa como lo hacen en el primer tiro, tampoco ...
Nathan Reed
0

Usaría el búfer de la plantilla. Despeje a 1 (preferiblemente al mismo tiempo que despeja la profundidad), dibuje su tabla. Luego habilite la prueba de plantilla, dibuje las sombras usando una textura de rectángulo borrosa, incrementando si la plantilla y la profundidad pasan, sin hacer nada si la plantilla falla, nada si la profundidad falla, y configure su función de plantilla en GL_EQUAL (ref 1, máscara 0xff), desactive la prueba de plantilla . (No he probado completamente esto, pero se deriva del código que hace algo similar y debería funcionar bien; es posible que deba ajustar los parámetros). Luego dibuja todo lo demás.

Las llamadas serían:

glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_EQUAL, 1, 2);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);

// draw shadow textures

glDisable (GL_STENCIL_TEST);

La única vez que esto puede causar problemas es si tiene dos bordes borrosos que se superponen ligeramente; de lo contrario, no necesita nada más que lo que ofrece OpenGL 1.1 básico y funcionará en todo el hardware (espere quizás las tarjetas 3DFX antiguas, que supongo que no está realmente preocupado por admitir ...)

Una segunda alternativa, que debería funcionar muy bien en un juego que no es crítico para el rendimiento, es glCopyTexSubImage2D. Eso también funcionará con una textura más pequeña que el backbuffer y también es compatible con todo el hardware (es parte de OpenGL 1.1 y Doom 3 lo usó, por lo que puede esperar que el soporte sea muy bueno).

La configuración básica sería así:

  • Color claro a negro.
  • Deshabilite la escritura de profundidad (aunque este método no necesita un búfer de profundidad, por lo que puede ignorar esa parte ya que no está usando uno).
  • Establezca una ventana gráfica con las mismas dimensiones que su textura.
  • Roba cartas como geometría rellena de blanco.
  • glCopyTexSubImage2D a su textura.
  • Vuelva a cambiar la ventana gráfica al tamaño de la ventana completa.
  • Dibuja la mesa como de costumbre.
  • Dibuje la textura como un quad mezclado de pantalla completa, usando un sombreador para desenfocarlo e invertir el color.
  • Dibuja todo lo demás.

Eso también debería funcionar muy bien, es un poco más intensivo en GPU que el método de búfer de plantilla, pero maneja el caso superpuesto correctamente y, como dije, creo que un juego como el tuyo tendrá potencia de GPU para grabar, incluso en un extremo bajo tarjeta.

Maximus Minimus
fuente