Quelles techniques de rendu devrais-je utiliser pour dessiner un effet d'ombre portée pour les cartes d'un jeu de cartes?

13

Quel type d'algorithme d'ombrage pourrait être utilisé pour créer des ombres comme celles-ci? entrez la description de l'image ici

celui que je fais est similaire mais tout est fait avec une API de dessin 2D optimisée par OpenGL donc il n'y a pas de coordonnée Z.

De plus, pour la main elle-même, j'aimerais vraiment avoir une sensation ombrée comme on le voit ici: entrez la description de l'image ici

Je ne sais tout simplement pas comment obtenir un aspect ombré proche de cela.

Le nombre de cartes est appelé à changer et les cartes sont jetées sur la table, donc je ne peux pas utiliser n'importe quel type de carte lumineuse.

Quels types d'algorithmes dois-je étudier (à part le flou que je sais que je vais devoir faire?)

Merci

Mise à jour

Je fais un jeu de cartes 2D. Je veux ajouter des ombres portées décalées par rapport aux cartes, un peu comme:

entrez la description de l'image ici

La façon dont je pense le faire est la suivante:

  • Gardez une texture de la même taille que le backbuffer.
  • Dessinez des rectangles sombres comme cartes de fortune avec cette texture.

  • Brouillez cette texture.

  • Dessine mes cartes avec cette texture.
  • Faites un éclairage supplémentaire sur les cartes.
  • Dessinez cette texture sur le backbuffer.

Mes questions sont:

  • Est-ce la bonne façon de procéder?

  • Existe-t-il un moyen de le faire sans rendre à la texture (en gardant un bitmap
    aussi gros que le backbuffer)?

  • Est-il sûr de supposer que la taille de texture maximale ne sera pas
    dépassée par la taille du backbuffer? (Ce que je veux dire, c'est que si le backbuffer
    est 2000x3000, est-il sûr de dire que je peux créer une texture dans
    la mémoire vidéo de cette taille?

Merci

jmasterx
la source
1
Un point esthétique sur votre deuxième problème: ce n'est pas vraiment possible si vous tenez réellement ces cartes dans votre main. Les cartes pressées les unes à côté des autres ne s'ombrissent pas sensiblement. Sauf si vous en tenez beaucoup . Vous ne pouvez pas vraiment tenir les cartes comme elles sont représentées dans cette image; ces cartes semblent séparées de plusieurs millimètres; ils ne sont pas à plat l'un contre l'autre. Je ne m'en inquiéterais pas.
Nicol Bolas

Réponses:

18

Je pense que tout le monde propose des solutions trop compliquées à ce problème ..

entrez la description de l'image ici

Donc tout d'abord, nous avons la carte (ou tout ce que vous voulez piocher), représentée ici par (a). Ensuite, nous en prenons une copie, la remplissons en noir et y exécutons un flou gaussien (b). Tout cela se produit dans Photoshop ou quel que soit votre outil d'art préféré.

Ensuite, dans le jeu, lorsque nous voulons dessiner la carte, dessinez d'abord l'image noire floue avec un mélange multiplicatif (ou alpha), décalez un peu dans une certaine direction, puis dessinez la carte par-dessus. Voilá.

Pour plus de ruse, vous pouvez alterner entre l'ombre et le rendu de carte pour obtenir un effet comme (d), ou dessiner d'abord toutes les ombres puis les cartes, comme dans (e) (j'ai coloré les cartes dans le cas (e) pour montrer qu'elles suis toujours séparé =)

Il est également préférable de ne pas utiliser de noir pur (ou alpha complet) pour que l'ombre crée des ombres plus subtiles et transparentes.

Jari Komppa
la source
2
+1 pour avoir fait les ombres hors du jeu. Vous pouvez également aller plus loin et modifier l'emplacement de l'ombre s'il y a de la lumière dans la scène.
FrenchyNZ
+1, belle illustration. De plus, dans le cas E, vous pouvez utiliser le rendu des ombres sombres sur la table et semi-clair sur les cartes avec pochoir. Ce sera plus compliqué, mais l'effet sera encore plus agréable :)
Kromster dit de soutenir Monica
2

Le premier n'est pas trop dur. Si vous effectuez le rendu d'un canal alpha pour votre main de cartes (qui peut être aussi simple que noir pour un pixel contenant une carte, et blanc pour transparent), vous pouvez effectuer tout type de flou que vous souhaitez sur le canal alpha uniquement, et puis le compenser et l'utiliser pour contrôler l'éclairage de la table. (Vraisemblablement, si vous n'avez pas de tampon Z, vous devez d'abord restituer le canal alpha hors écran quelque part, puis faire le tableau avec le masque, puis rendre les cartes réelles.)

Le second ressemble un peu à SSAO (occlusion ambiante écran-espace). Cette technique nécessite une coordonnée Z. Cependant, si vous n'avez pas les angles variables entre les cartes (c'est ce que je suppose si vous n'avez pas de Z-buffer), vous pouvez probablement faire une assez bonne approximation en rendant une ombre portée (comme la première) pour chaque carte. La performance pourrait être un peu délicate, cependant: chaque avion aurait besoin d'un canal alpha flou pour tous les plans au-dessus, et s'il y a un tas de cartes sur la table, cela pourrait être quelques passes de rendu.

John Calsbeek
la source
SSAO est exagéré =) Il est très difficile de dire quelle technique d'observation est utilisée sans voir l'exemple animé. Si les cartes tombent toujours dans cet ordre et cet espacement les unes sur les autres, il serait plus facile de simplement pré-rendre les ombres, mais vous ne sauriez jamais sans voir le jeu en action.
Patrick Hughes
0

Pourriez-vous pas faire une carte d'ombre? Rendez la scène à un fbo. Enregistrez uniquement les valeurs de profondeur et effectuez la vérification de la valeur de profondeur normale dans le shader pour voir si une ombre doit être rendue ou non.

Joey Green
la source
Je n'utilise pas de tampon Z, il n'y a pas de "profondeur".
jmasterx
0

Le processus suivant ne nécessite pas de cible de rendu hors écran. Cependant, ce faisant, il gagne l'exigence que le tableau soit dessiné en premier . Ou du moins, rien n'est dessiné sur les pixels que le tableau couvrira avant que le tableau ne soit dessiné. Cela nécessite également que la table elle-même soit une pièce unique et sans chevauchement: une image.

De plus, votre framebuffer a besoin d'un composant alpha.

  1. Obtenez une image en niveaux de gris d'une carte. Rendez-le flou sur les bords, augmentant éventuellement sa taille. Ceci est votre image de carte fantôme. Notez qu'il s'agit d'une image monocanal. Lorsque vous accédez à cette texture dans votre shader, vous devez vous assurer que vous placez la valeur unique dans le composant alpha. Cela peut être fait dans votre shader ou ailleurs.

    Une valeur de 0,0 dans l'image signifie qu'il n'y a pas d'ombre. Une valeur de 1,0 dans l'image signifie une ombre totale . Autrement dit, complètement noir. Vous voulez probablement une valeur de 0,5 ou plus comme couleur la plus foncée.

  2. Effacez l'écran de sorte que l'alpha soit mis à zéro .

  3. Avant de rendre quoi que ce soit (ou du moins tout ce qui sera rendu "sous" le tableau), pour chaque carte, restituez la texture floue, décalée de la position réelle de la carte (mais avec la même orientation). La couleur sortie par le shader doit être La configuration de mélange pour cela doit être (dans le langage OpenGL):

    glBlendEquation(GL_MAX);

    Ce mode de fusion est utilisé pour empêcher les ombres qui se chevauchent de devenir de plus en plus sombres ou plus claires. Il prend simplement la valeur la plus sombre écrite sur ce pixel. Il devrait être assez beau.

    Vous devez également utiliser le masque d'écriture couleur pour désactiver les écritures couleur.

  4. Rendez la table. Dans ce cas, le mélange doit être configuré comme suit:

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

Si les restrictions sont trop restrictives pour vous, vous devez utiliser une cible de rendu. Cela se fait comme suit:

  1. Créez l'image de la carte fantôme comme précédemment.

  2. Tout d'abord, rendez les ombres. Liez le tampon d'image ombré (qui ne doit être qu'une image à canal unique, si votre matériel peut rendre à l'un d'eux). Effacez sa valeur à zéro.

  3. Pour chaque carte, restituez l'image de la carte fantôme, décalée comme précédemment. Votre shader doit écrire la même valeur sur les quatre composants de la couleur de sortie. Le mode de fusion devrait de nouveau l'être glBlendEquation(GL_MAX).

  4. Revenez au framebuffer standard. Dessinez tout ce que vous souhaitez masquer.

  5. Maintenant, dessinez un quadruple plein écran avec une image d'ombre que nous avons rendue. Le shader doit stocker le texel extrait de l'image d'ombre dans l'alpha de la sortie; le RVB n'est pas pertinent. Le mode de fusion doit être:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
Nicol Bolas
la source
Dans la première méthode, je pense que vous avez oublié l'étape 5: désactiver le mélange et rendre les cartes. En outre, il convient de noter que la première méthode ne vous permet pas d'obtenir des ombres inter-cartes comme le montre la deuxième capture d'écran de l'OP.
Nathan Reed
@NathanReed: Je pensais qu'il savait comment arrêter les choses lui-même. De plus, les "ombres inter-cartes" n'ont aucun sens, comme je l'ai souligné dans mon commentaire sous la question.
Nicol Bolas
1
Cela ne représente peut-être pas de façon réaliste la façon dont vous détenez les cartes, mais ça a l'air cool! Cela n'a pas vraiment de "sens" que les cartes flottent au-dessus de la table comme elles le font lors du premier tir, non plus ...
Nathan Reed
0

J'utiliserais le tampon de pochoir. Videz-le à 1 (de préférence en même temps que vous nettoyez la profondeur), dessinez votre table. Ensuite, activez le test du pochoir, dessinez les ombres à l'aide d'une texture de rectangle flou, incrémentez si le pochoir et la profondeur passent, ne faites rien si le pochoir échoue, rien si la profondeur échoue, et définissez votre fonction de pochoir sur GL_EQUAL (réf 1, masque 0xff), désactivez le test du pochoir . (Je n'ai pas entièrement testé cela, mais il est dérivé d'un code similaire et devrait fonctionner correctement; vous devrez peut- être modifier les paramètres). Dessinez ensuite tout le reste.

Les appels seraient:

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

// draw shadow textures

glDisable (GL_STENCIL_TEST);

La seule fois où cela peut causer des problèmes, c'est si vous avez deux bords flous qui se chevauchent légèrement; sinon, il n'a besoin de rien de plus que ce qu'OpenGL 1.1 de base offre et fonctionnera sur tout le matériel (attendez-vous peut-être aux anciennes cartes 3DFX, que je suppose que vous n'êtes pas vraiment inquiet à propos du support ...)

Une deuxième alternative, qui devrait très bien fonctionner dans un jeu sans performances critiques, est glCopyTexSubImage2D. Cela fonctionnera avec une texture plus petite que le backbuffer et est également bien pris en charge sur tout le matériel (il fait partie d'OpenGL 1.1 et Doom 3 l'a utilisé, vous pouvez donc vous attendre à ce que le support soit très bon).

La configuration de base se présenterait comme suit:

  • Couleur claire au noir.
  • Désactivez l'écriture en profondeur (bien que cette méthode ne nécessite pas de tampon de profondeur, vous pouvez donc ignorer cette partie car vous n'en utilisez pas).
  • Définissez une fenêtre avec les mêmes dimensions que votre texture.
  • Piochez des cartes sous forme de géométrie remplie de blanc.
  • glCopyTexSubImage2D à votre texture.
  • Remettez la fenêtre d'affichage en taille de fenêtre complète.
  • Dessinez la table comme d'habitude.
  • Dessinez la texture comme un quadrilatère plein écran, en utilisant un shader pour la rendre floue et inverser la couleur.
  • Dessinez tout le reste.

Cela devrait également très bien fonctionner, c'est un peu plus gourmand en GPU que la méthode du tampon de pochoir mais gère correctement le cas de chevauchement et - comme je l'ai dit - je pense qu'un jeu comme le vôtre aura la puissance du GPU à graver, même sur un bas de gamme carte.

Maximus Minimus
la source