Que diriez-vous quelque chose comme ça?
Ne dessinez pas votre éclairage en teintant vos sprites de tuiles. Dessinez vos tuiles non éclairées sur une cible de rendu, puis dessinez les lumières des tuiles sur une deuxième cible de rendu, représentant chacune sous la forme d'un rectangle en niveaux de gris couvrant la zone de la tuile. Pour rendre la scène finale, utilisez un shader pour combiner les deux cibles de rendu, assombrissant chaque pixel du premier en fonction de la valeur de la seconde.
Cela produira exactement ce que vous avez maintenant. Cela ne vous aide pas, alors changeons-le un peu.
Modifiez les dimensions de votre cible de rendu lightmap de sorte que chaque mosaïque soit représentée par un seul pixel , plutôt que par une zone rectangulaire. Lors de la composition de la scène finale, utilisez un état d'échantillonneur avec filtrage linéaire. Sinon, laissez tout le reste inchangé.
En supposant que vous avez correctement écrit votre shader, le lightmap devrait être effectivement "agrandi" pendant la composition. Cela vous donnera un bel effet de dégradé gratuitement via l'échantillonneur de texture du périphérique graphique.
Vous pouvez également couper le shader et le faire plus simplement avec un BlendState `` assombrissant '', mais je devrais l'expérimenter avant de pouvoir vous donner les détails.
MISE À JOUR
J'ai eu un peu de temps aujourd'hui pour me moquer de ça. La réponse ci-dessus reflète mon habitude d'utiliser des shaders comme première réponse à tout, mais dans ce cas, ils ne sont pas réellement nécessaires et leur utilisation complique inutilement les choses.
Comme je l'ai suggéré, vous pouvez obtenir exactement le même effet en utilisant un BlendState personnalisé. Plus précisément, ce BlendState personnalisé:
BlendState Multiply = new BlendState()
{
AlphaSourceBlend = Blend.DestinationAlpha,
AlphaDestinationBlend = Blend.Zero,
AlphaBlendFunction = BlendFunction.Add,
ColorSourceBlend = Blend.DestinationColor,
ColorDestinationBlend = Blend.Zero,
ColorBlendFunction = BlendFunction.Add
};
L'équation de mélange est
result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)
Donc, avec notre BlendState personnalisé, cela devient
result = (lightmapColor * destinationColor) + (0)
Ce qui signifie qu'une couleur source de blanc pur (1, 1, 1, 1) conservera la couleur de destination, une couleur source de noir pur (0, 0, 0, 1) assombrira la couleur de destination en noir pur, et tout une nuance de gris entre les deux assombrira la couleur de destination d'une quantité moyenne.
Pour mettre cela en pratique, faites d'abord tout ce que vous devez faire pour créer votre lightmap:
var lightmap = GetLightmapRenderTarget();
Ensuite, dessinez simplement votre scène non éclairée directement dans le backbuffer comme vous le feriez normalement:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();
Puis dessinez la lightmap en utilisant le BlendState personnalisé:
var offsetX = 0; // you'll need to set these values to whatever offset is necessary
var offsetY = 0; // to align the lightmap with the map tiles currently being drawn
var width = lightmapWidthInTiles * tileWidth;
var height = lightmapHeightInTiles * tileHeight;
spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
spriteBatch.Draw(lightmap, new Rectangle(offsetX, offsetY, width, height), Color.White);
spriteBatch.End();
Cela multipliera la couleur de destination (tuiles non éclairées) par la couleur source (lightmap), assombrissant les tuiles non éclairées de manière appropriée et créant un effet de dégradé à la suite de la mise à l'échelle de la texture lightmap jusqu'à la taille nécessaire.
D'accord, voici une méthode très simple pour créer un éclair 2D simple et fluide, rendu en trois passes:
Au col 1, vous dessinez tous les sprites et le terrain.
Dans le passage 2, vous dessinez un deuxième groupe de sprites qui sont les sources de lumière. Ils devraient ressembler à ceci:
initialisez la cible de rendu avec du noir et dessinez ces sprites dessus avec un mélange maximum ou additif.
Dans la passe 3, vous combinez les deux passes précédentes. Il existe plusieurs façons de les combiner. Mais la méthode la plus simple et la moins artistique est de les mélanger via Multiply. Cela ressemblerait à ceci:
la source
Le deuxième lien que vous avez publié ressemble à un brouillard de guerre en quelque sorte, il y a quelques autres questions à ce sujet
Cela me ressemble à une texture , où vous "effacez" les bits de la superposition noire (en définissant l'alpha de ces pixels à 0) lorsque le joueur avance.
Je dirais que la personne doit avoir utilisé un pinceau de type "effacer" là où le joueur a exploré.
la source
Des sommets légers (coins entre les carreaux) au lieu de carreaux. Mélanger l'éclairage sur chaque tuile en fonction de ses quatre sommets.
Effectuez des tests de visibilité directe sur chaque sommet pour déterminer son allumage (vous pouvez soit faire bloquer un bloc de toute lumière ou diminuer la lumière, par exemple, compter le nombre d'intersections à chaque sommet combinées à la distance pour calculer une valeur de lumière plutôt que d'utiliser un test binaire pur visible / non visible).
Lors du rendu d'une tuile, envoyez la valeur lumineuse de chaque sommet au GPU. Vous pouvez facilement utiliser un fragment shader pour prendre la valeur de la lumière interpolée à chaque fragment dans le sprite de la tuile pour éclairer chaque pixel en douceur. Cela fait assez longtemps que je n'ai pas touché GLSL que je ne me sentirais pas à l'aise de donner un véritable échantillon de code, mais en pseudo-code, ce serait aussi simple que:
Le vertex shader n'a qu'à transmettre les valeurs d'entrée au fragment shader, rien de compliqué même à distance.
Vous obtiendrez un éclairage encore plus doux avec plus de sommets (par exemple, si chaque tuile est rendue en quatre sous-tuiles), mais cela ne vaut peut-être pas la peine en fonction de la qualité que vous recherchez. Essayez-le d'abord de la manière la plus simple.
la source
line-of sight tests to each vertex
? Ça va coûter cher.