2 votes

Formule simple du mode 7 / exemple ?

J'ai récemment découvert l'effet pseudo-3d qui utilisait le mode 7 de la SNES, et je veux essayer de le reproduire dans le moteur Godot. J'ai essayé de faire des recherches en ligne, mais tout était soit expliqué d'une manière que je ne pouvais pas comprendre, soit dans un langage de programmation que je ne connaissais pas. J'ai également besoin d'apprendre comment faire pivoter la zone, et mettre des sprites comme personnages ou ennemis, mais je n'ai rien trouvé à ce sujet. Quelqu'un peut-il m'expliquer la formule, ainsi que la façon dont je pourrais la mettre en œuvre ?

3voto

Theraot Points 5174

Ok, j'ai compris. Il y a deux types d'installation que je vais expliquer.

Avant d'en arriver là, laissez-moi vous expliquer le code du shader que nous allons utiliser :

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV, 1.0);
    COLOR = texture(TEXTURE, uv.xy / uv.z);
}

Il s'agit d'un canvas_item En tant que tel, il est destiné à fonctionner en 2D. Ce que nous faisons, c'est appliquer une matrice de transformation (passée en tant que uniform ) aux coordonnées de la texture ( UV ). Le résultat que nous stockons dans le uv variable. Nous allons l'utiliser pour échantillonner la texture de n'importe quel noeud utilisant ce shader Cependant, nous devons utiliser la variable z de uv pour faire un effet de perspective. Pour ce faire, nous divisons uv.xy par uv.z .

Cependant, je veux l'appliquer de manière centrée sur la texture. Donc, laissez-moi soustraire 0.5 au début, et ajoutez le 0.5 à la fin :

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5, 1.0);
    COLOR = texture(TEXTURE, (uv.xy / uv.z) + 0.5);
}

Une dernière chose. Je n'aime pas que sur les valeurs extrêmes, on voit une image inversée. Donc, je vais gérer ça comme ça :

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5, 1.0);
    if (uv.z < 0.0) discard;
    COLOR = texture(TEXTURE, (uv.xy / uv.z) + 0.5);
}

Voici une alternative pour les adeptes du sans-branche (je ne sais pas si elle est meilleure) :

shader_type canvas_item;
uniform mat3 matrix;

void fragment()
{
    vec3 uv = matrix * vec3(UV - 0.5, 1.0);
    COLOR = texture(TEXTURE, (uv.xy / uv.z) + 0.5);
    COLOR.a *= sign(sign(uv.z) + 1.0);
}

Ici sign(uv.z) sera soit -1.0 , 0.0 o 1.0 .

Puis sign(uv.z) + 1.0 ce sera soit 0.0 , 1.0 o 2.0 .

Enfin sign(sign(uv.z) + 1.0) sera soit 0.0 o 1.0 (vous pouvez utiliser clamp(sign(uv.z), 0.0, 1.0) à la place si vous préférez). Et ainsi COLOR.a *= sign(sign(uv.z) + 1.0) c'est multiplier alpha par 0.0 partout uv.z est négatif.


Note : La raison pour laquelle je manipule les coordonnées UV dans le fragment shader au lieu de le faire dans le vertex shader est que Godot fait du mapping de texture affine pour la 2D. Ce qui entraînerait une distorsion. C'est une solution de contournement.


La première configuration est simplement un sprite. Définissez un Sprite avec la texture que vous voulez, et définissez le matériau comme un nouveau matériau de shader, et dans le shader, utilisez le code que j'ai montré au début.

Godot vous donnera l'option d'éditer le fichier uniform mat3 matrix sous Shader Param dans la ressource matérielle. Par défaut, il s'agit de la matrice d'identité, qui ressemble à ceci dans l'éditeur :

x 1  y 0  z 0
x 0  y 1  z 0
x 0  y 0  z 1

Vous pouvez l'utiliser pour appliquer une rotation, une mise à l'échelle, un cisaillement ou des transformations de perspective. *Je suggère de commencer par changer les zéros de la colonne z (la plus à droite), qui contrôle la perspective :

x 1  y 0  z 3d_rotate_horizontal
x 0  y 1  z 3d_rotate_vertical
x 0  y 0  z scale

Exemple de résultat :

Robot with no effect and Robot with perspective effect

Une recommandation : N'utilisez pas une texture qui va jusqu'au bord. Lorsque vous appliquez la perspective, le shader lira au-delà du bord, mais la texture ne sera pas lue. par défaut elle est serrée, ce qui a pour conséquence d'étirer tous les pixels au bord de la texture.

À propos, si vous importez des images en tant que Image (au lieu de Texture qui est la valeur par défaut), vous pouvez définir la texture du Sprite en tant que ImageTexture qui vous donnera un contrôle supplémentaire sur la façon dont la texture s'affiche, y compris l'activation de mipmap, le filtre antialias, et la répétition de la texture au-delà de son bord (avec ou sans miroir).


La deuxième configuration, plus complexe, concerne les objets multiples. C'est également la configuration qui fonctionne pour un TileMap . Vous allez avoir besoin de cette structure arborescente :

- Sprite2D
  +- Viewport
     +- Camera2D
     +- target

Positionner le Sprite2D où nous voulons voir cela, donnez-lui un matériau de shader avec le code de shader que j'ai montré au début. D'ailleurs, cela devrait également fonctionner avec une TextureRect au cas où vous en auriez besoin dans l'interface utilisateur.

Ne définissez pas de texture pour le Sprite2D (o TextureRect ). Vous allez joindre un script qui ressemble à ceci :

extends Sprite

func _ready():
    var viewport = $Viewport
    yield(get_tree(), "idle_frame")
    yield(get_tree(), "idle_frame")
    texture = viewport.get_texture()

Changement Sprite a TextureRect si nécessaire.

Ce code prend une référence à la Viewport et attend deux trames (pour s'assurer que le noeud de l'opération est bien en cours). Viewport est disponible), puis il prend la texture et se l'attribue.

Vous devez donner au Viewport la taille que vous souhaitez. Je suggère également de définir Transparent Bg y V Flip . Le site Camera2D peut conserver ses valeurs par défaut.

Enfin, la "cible" est ce que vous voulez montrer. Cela peut être un ou plusieurs noeuds 2D. Je suggère d'en faire une autre scène, de cette façon il sera facile de l'éditer indépendamment de cette configuration (ce qui est enfant de l'élément Viewport ne sera pas visible dans l'éditeur).

Exemple de résultat :

TileMap with perspective effect and Robot ontop with no effect

Oui, nous aurions pu archiver ce même effet avec de la vraie 3D dans Godot, sans problème. Mais nous ne l'avons pas fait. Nous avons choisi de mettre en œuvre cet effet avec des outils 2D et de faire les autres choses, non pas parce qu'elles sont faciles, mais parce qu'elles sont difficiles.


Les textures utilisées dans cette réponse sont du domaine public (CC0), à partir de Kenney .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X