Comment puis-je mettre en œuvre un éclairage fluide basé sur des carreaux?

8

Je travaille sur un jeu de tuiles 2D et j'ai mis en place un éclairage à bords durs:

entrez la description de l'image ici

Je veux que ça soit un peu lissé. Je n'ai pas besoin d'ombres ou quoi que ce soit, juste un simple éclairage. Je voudrais qu'il ressemble davantage à ceci:

entrez la description de l'image ici

Mon système actuel utilise des niveaux de lumière pour chaque tuile dans le monde et ils sont recalculés lorsqu'une tuile est placée ou retirée. J'utilise batch.setColor(...)pour ombrer les carreaux. Quelle est la bonne façon d'obtenir cet éclairage doux?

Je ne veux pas utiliser la méthode de superposition de la carte lumineuse, j'ai déjà essayé et je n'étais pas satisfait du résultat. Je veux pouvoir définir la quantité de lumière qui peut traverser un bloc. Par exemple, un bloc de terre doit absorber une partie de la lumière, mais un bloc de verre ne doit pas bloquer la lumière. Ce n'était pas vraiment possible avec la méthode de superposition de cartes claires. MISE À JOUR: J'ai mal compris ce qu'est réellement cette méthode. Je comprends maintenant. Je pensais dans le mauvais sens. Désolé!

ProRed
la source
Pour être honnête, il a l'air plus élégant avec un éclairage à bords durs.
S. Tarık Çetin
Je n'aime pas trop ça, aussi c'est un peu difficile de différencier les tuiles de fond et les tuiles de premier plan avec ce style.
ProRed

Réponses:

15

Un moyen simple d'obtenir un éclairage fluide dans un jeu basé sur des tuiles consiste à dessiner une "lightmap" sur une cible de rendu, puis à dessiner cette cible de rendu sur votre scène tout en la mélangeant alpha.

La cible de rendu de votre carte lumineuse aurait la taille de votre carte de tuiles, mais en pixels. Chaque pixel représenterait la couleur claire de sa tuile correspondante. Cette texture de rendu ressemblerait à ceci (texture en haut à gauche en noir et blanc):

entrez la description de l'image ici

Une fois que vous avez cette texture de carte légère, vous pouvez ensuite la dessiner en superposition sur votre monde de jeu (étiré). Vous devrez le serrer correctement, afin qu'il s'étende parfaitement sur vos tuiles dans le monde du jeu.

Ensuite, il s'agit d'alpha mélanger cette texture sur votre monde de jeu dans libGDX. Afin de se fondre dans LibGDX (personnellement, je ne sais pas comment), vous devrez peut-être regarder la Gdx.gl.glBlendFuncfonction.

jgallant
la source
2
Vous pouvez contrôler l'éclairage comme vous le souhaitez avec ce système. Je ne sais pas à quoi vous faites référence lorsque vous dites que vous ne pouvez pas bloquer la lumière. De plus, vous ne savez pas exactement comment vous envisagez de lisser votre système actuel, car vous ne faites que colorer vos carreaux.
jgallant
4
Soit dit en passant, ce système est la façon dont Starbound le fait.
Qqwy
2
C'est une excellente approche et permet une flexibilité là où elle est nécessaire. J'utilise ceci dans mon jeu basé sur des tuiles où je n'ai pas accès aux shaders, et cela fonctionne très bien!
Tyyppi_77
1
MISE À JOUR : Cela semble être la voie à suivre, j'ai mal compris cette méthode et je comprends maintenant parfaitement! Je vais essayer d'implémenter cette méthode maintenant et je vais marquer cela comme la meilleure réponse et vous donner la prime!
ProRed
2
Si vous avez d'autres questions sur la façon de le faire, n'hésitez pas à demander. J'ai implémenté cela, et @ Tyyppi_77 l'a aussi récemment. Je l'ai fait dans XNA / Monogame et Unity. Tyyppi l'a fait en SDL.
jgallant
4

une façon indépendante du moteur de le faire est d'utiliser une cartographie de la lumière moyenne. Tout d'abord, vous devez générer une carte en noir et blanc sous la forme d'un tableau 2D de booléens de la taille du monde où les blocs sont Vrai et vide est Faux.

Comme ceci (1 est noir, 0 est blanc): carte

Ensuite, vous devez créer un nouveau tableau 2D qui est de la même taille que le premier tableau mais est un tableau de flottants. Ensuite, vous passez d'un bloc noir (vrai) à un bloc noir dans le tableau et faites la moyenne de la valeur échantillonnée à proximité (expliquée ci-dessous)

Cette image vous aidera: moyenne

Cette image représente l'échantillonnage (où + signifie faux et | signifie vrai). ce que nous faisons est de traiter les valeurs vraies comme 1 et les fausses valeurs comme 0. Ensuite, vous faites la moyenne des 9 nombres et les placez dans la bonne partie du tableau. REMARQUE: assurez-vous que lorsque vous échantillonnez des bords, vous utilisez les valeurs externes comme sensibles au contexte. Par exemple: sous terre, la carte en dehors du monde pourrait être 1 et le ciel devrait être 0.

Il devrait ressembler à ceci (extrait d'un autre article):fin

Ensuite, tout ce que vous avez à faire est de teinter chaque bloc du tableau avec

rgba(tint,tint,tint,1)

(teinte = la valeur de bloc moyenne actuelle dans le deuxième tableau et alpha n'a pas d'importance). Remarque: cela suppose que la pseudo-fonction rgba prend des flottants de 0-1 au lieu de 0-255, si c'est le cas, faites simplement ceci:

rgba(tint*255,tint*255,tint*255,255)

J'espère que cela fait un peu de sens :) Si vous voulez du code, demandez-le!

UDXS
la source
Fist off merci pour votre réponse, mais le fait est que j'ai déjà un éclairage hard-edge dans mon jeu ( ici ). J'ai demandé comment je pouvais changer cela pour avoir l'air plus lisse ( comme ça )
ProRed
1

Puisque vous parlez de choses qui bloquent la lumière, je suppose que vous avez un modèle de diffusion de la lumière. Par exemple, tout sans blocs au-dessus est entièrement éclairé, la lumière se propage à toutes les cellules voisines mais perd une certaine luminosité.

Vous devriez être en mesure d'implémenter ces règles assez facilement du côté logiciel, au moins la partie de lissage consiste simplement à jeter un ombrage sur la carte de lumière que vous avez générée.

Les méthodes que d'autres ont suggérées pour superposer une carte lumineuse sont quelque chose que vous devriez faire de toute façon. Mais vous pouvez changer la façon dont vous générez cette carte lumineuse. Vous pouvez initialement le remplir uniquement avec les informations de bloc, mais vous pouvez ensuite le mettre à l'échelle et le lisser dans un shader par exemple. Un avantage supplémentaire de l'approche de la carte de la lumière est que vous pouvez simplement dessiner des lumières dynamiques dans votre carte de la lumière pour mettre en évidence des explosions ou ce que vous avez et elle se fondra naturellement avec le reste de votre monde.

Mélange additif dans votre carte de lumière, puis mélange multiplicatif de votre carte de lumière avec le monde du jeu.

Je l'ai fait il y a quelque temps en utilisant les mêmes principes. Ce système ne prend pas en charge la chute de lumière différemment pour différents types de terrain, mais au moins il devrait illustrer l'utilité de superposer une carte lumineuse.

Nils Ole Timm
la source
Je vois, donc je rendrais les niveaux de lumière sous forme de rectangles qui sont exactement de la taille de la tuile correspondante à une deuxième cible de rendu? Et comment pourrais-je le lisser?
ProRed
Vous pouvez laisser le GPU le gérer en le sous-échantillonnant, car lors du rendu, il sera juste interpolé linéairement pour vous. Si ce n'est pas assez bon, vous pouvez exécuter une sorte de flou dessus dans un shader. Vous pouvez également envisager de rendre avec une granularité plus fine que la résolution des tuiles si vous souhaitez la dessiner différemment selon les tuiles adjacentes. Fondamentalement, la partie difficile consiste à définir les règles spécifiques que vous souhaitez pour quelle zone doit être allumée. Si vous écrivez ces règles, vous trouverez généralement un moyen assez simple de le faire.
Nils Ole Timm
1

C'est assez facile pour une torche: en utilisant un pixel shader personnalisé, vous calculez la distance entre chaque fragment et la torche; vous pouvez ensuite calculer où la première tuile dense qui bloque la lumière provenant de la torche. Vous calculez ensuite la distance où la lumière n'est pas bloquée, multipliez cela par quelque chose <1 pour que la torche n'éclaire pas le soleil, soustrayez-la de la distance totale et répétez pour le reste de la distance (où la lumière a été bloquée par à au moins une tuile) avec une valeur multipliée bien plus petite ... Je sais comment faire ce calcul et ce n'est pas trop compliqué à implémenter en opengl.

EDIT: pour une source lumineuse simple avec un point central spécifique, ma méthode est extrêmement simple. Cependant, le mien ne fonctionne pas avec la lumière du soleil, mais bien que la carte alpha fonctionne très bien pour la lumière du soleil, ce ne serait PAS une bonne idée pour une torche, étant donné qu'il s'agit potentiellement d'un objet en mouvement, et faire une nouvelle carte chaque image n'est pas agréable expérience de la vie. La meilleure solution à mon avis est un mélange: calcul de la distance pour des lumières spécifiques qui sont en fait des objets dans le jeu, un shader séparé que vous venez de jeter au-dessus de la carte alpha que vous avez générée de manière procédurale en utilisant la technique mentionnée ci-dessus: une texture de tous les tuiles alphas de votre ombrage dur, comme beaucoup de carrés, et jouer avec les techniques pour le lisser.

Paul Boursin
la source
0

Votre rendu utilise-t-il les couleurs des sommets (ou pouvez-vous le changer)?

En supposant que chaque bloc est un carré à 4 sommets, cela vous donnerait quelques options, par exemple:

Si votre algorithme d'éclairage actuel vous donne une valeur lumineuse par bloc, vous pouvez le modifier pour vous donner une valeur par sommet. Alternativement, à chaque sommet, vous pouvez faire la moyenne de la couleur claire du bloc actuel plus ses trois voisins. L'une ou l'autre solution serait peu coûteuse.

Programmeur de jeux chroniques
la source