Modèle 3D dans un menu !
-
Sommaire
Introduction
Hey ! Ca fait longtemps que j’ai pas fait de tutoriels ! Je me lance donc pour un tutoriel qui pour ma part est fort sympathique tellement il y a d’utilisations !
Je parle bien entendu de nos magnifiques modèles 3D que nous faisons sur Techne et puis qui finissent malencontreusement dans la corbeille (R.I.P ma tente), MAIS je m’éloigne du sujet !
Car ce que nous pourrons faire avec cette technologie dépasse l’entendement !
Ouais non en fait c’est juste de l’OpenGL et un bon vieux GUI !Aujourd’hui donc ! Nous apprendrons à faire un rendu de nos modèles 3D dans un GUI/Menu !
Pré-requis
- Éclipse (normal)
- Forge
- Et quelques connaissance en OpenGL !
Connaissance que je n’ai d’ailleurs pas, car pour arriver à ce résultat j’ai procédé par d’ÉNORMES batteries de tests !
(Comme quoi tout le monde peut le faire :D)
Code
Un GUI Basique:
Bon dois-je vous apprendre à faire un GUI Basique ?
Bon d’accord !
Je vous file ma classe vierge mais qui contient toutes les explications à la création d’un GUI Basique !
package tuto.modeletroisD.gui; @SideOnly(Side.CLIENT) public class GuiModeleTROISD extends GuiScreen { //Compteur qui se met à jour private int updateCounter; /** * Ajouter des boutons (ou autres fonction) dans le menu concerné */ public void initGui() {} /** * Action exécutée lors d'un "clique" sur un bouton */ protected void actionPerformed(GuiButton par1GuiButton) {} /** * Fonction pour "update" "mettre à jour" le GUI */ public void updateScreen() { super.updateScreen(); ++this.updateCounter; } /** * Afficher différentes fonctions sur le GUI (texte, modèle 3D, Items...) */ public void drawScreen(int par1, int par2, float par3) { super.drawScreen(par1, par2, par3); } }
Je vous ai déjà fourni le ++this.updateCounter; qui reste basique !
Il faut bien que le GUI extends GuiScreen !
Ensuite nous allons faire appel à un model 3D qui supportera notre GUI !
Faire appel à notre modèle 3D:
Rien de plus simple !
Juste après,
private int updateCounter;
Ajoutons ceci:
private static ModelTROISD modelTroisD = new ModelTROISD();
Car le petit modelTroisD nous permettra de faire appel à tout ce qui ce trouve dans la classe ModelTROISD s’pas cool ça ?
Ensuite il faut peut-être lui mettre une texture à notre modèle non ?
Je pense que c’est mieux oui !public static final ResourceLocation modelTroisDTexture = new ResourceLocation("modID:" + "texture/vers/le/modele3D.png");
Mettez-le juste en dessous de,
private static ModelTROISD modelTroisD = new ModelTROISD();
Et c’est pas fini !
Il nous faut une une fonction pour aller chercher le render, modifié, comme dans le tutoriel;
Rendu complexe de bloc via TESR
Et je vais utiliser ce bout de code:
GL11.glPushMatrix(); GL11.glTranslated(x + 0.5F, y + 1.5F, z + 0.5F); this.bindTexture(textureLocation); GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F); this.model.render(0.0625F); GL11.glPopMatrix();
Que j’ai modifié en ceci:
public void modeleTROISD(int par1, int par2, float par3) { GL11.glPushMatrix(); GL11.glScalef(1.0F, 1.0F, 1.0F); GL11.glColor3f(1.0F, 1.0F, 1.0F); drawModelTROISD(par1, par2, par3); GL11.glPopMatrix(); }
Normalement vous aurez une erreur sur drawModelTROISD, car la fonction n’existe pas, nous allons donc la créer !
Mais ce sera dans la prochaine partie !Checkpoint :
A ce stade votre classe devrait ressembler à ça:
package tuto.modeletroisD.gui; //A vous de voir si vous avez des imports à faire //Rappel CTRL + MAJ + O @SideOnly(Side.CLIENT) public class GuiModeleTROISD extends GuiScreen { //Compteur qui se met à jour private int updateCounter; private static ModelTROISD modelTroisD = new ModelTROISD(); public static final ResourceLocation modelTroisDTexture = new ResourceLocation("modID:" + "texture/vers/le/modele3D.png"); /** * Ajouter des boutons (ou autres fonction) dans le menu concerné */ public void initGui() {} /** * Action exécutée lors d'un "clique" sur un bouton */ protected void actionPerformed(GuiButton par1GuiButton) {} /** * Fonction pour "update" "mettre à jour" le GUI */ public void updateScreen() { super.updateScreen(); ++this.updateCounter; } /** * Afficher différentes fonctions sur le GUI (texte, modèle 3D, Items...) */ public void drawScreen(int par1, int par2, float par3) { super.drawScreen(par1, par2, par3); } public void modeleTROISD(int par1, int par2, float par3) { GL11.glPushMatrix(); GL11.glScalef(1.0F, 1.0F, 1.0F); GL11.glColor3f(1.0F, 1.0F, 1.0F); drawModelTROISD(par1, par2, par3); GL11.glPopMatrix(); } }
Le point précision :
On va faire une petite pause pour que je puisse vous expliquer, surtout aux débutants, experts passez à l’étape suivante !
(Ce message et difficile à faire passer et comprendre aux autres)Pour vous expliquer donc, comme je procède, je ne me classe pas dans le niveau des super moddeurs qui ont appri par coeur le Java ! Je me classe comme étant un débrouillard, un curieux !
Oui car pour arriver à ce résultat là j’ai n’ai eu besoin que de Minecraft et de différents programmes qui affiche de simples modèles 3D
Bien sûr mes autres tutoriels ont soit été faits à partir d’une aide soit à partir d’un détournement de tutoriel, détournement n’étant pas le bon mot !
Bref simplement pour dire qu’avec un peu de temps de logique et de curiosité on arrive à beaucoup de choses de nos jours !
Et que tout le monde peut le faire !FIN de la parenthèse un peu nulle
Draw du modèle 3D :
ATTENTION ! %(#FF0000)[Ce qui suit ne possèdera pas d’explications claires ! Voir pas d’explications par endroit !
Je vous demanderais donc un peu d’indulgence et si quiconque a son lots d’explications à apporter, ou pour m’éclairer je modifierais le sujet en tant que tel !Je suis tombé sur ces fonctions d’OpenGL en faisant des recherches sur le net, qui n’ont pas toujours d’explications, et en m’aidant de la classe du GuiEnchantTable, un truc comme ça.]
Nous entrons dans la partie ou j’ai fais énormément de tests avant d’arriver à un stade bien sympathique !
Je vais vous expliquer, ce que je sais, les différents appels que je passe à OpenGL !
Vous pouvez aussi lire dans les commentaires car Xavpok a expliqué plus en détails les fonctions OpenGL !
Pour commencer,
public void drawModelTROISD(int par0, int par1, float par2) { }
Puis je vais ajouter des lignes de code que j’essaierais de vous expliquer !
GL11.glPushMatrix(); GL11.glMatrixMode(5889); GL11.glPushMatrix(); GL11.glLoadIdentity();
Explications:
L’int 5889, ne doit pas être changé car vous aurez une erreur OpenGL qui sera répétée en boucle dans la fonction et votre modèle 3D ne s’affichera pas, le MatrixMode est en rapport avec LoadIdentity.
A la suite ajoutons,
ScaledResolution scaledresolution = new ScaledResolution(this.mc.gameSettings, this.mc.displayWidth, this.mc.displayHeight); GL11.glViewport((scaledresolution.getScaledWidth() - 140) / 2 * scaledresolution.getScaleFactor(), (scaledresolution.getScaledHeight() - 140) / 2 * scaledresolution.getScaleFactor(), 512 * scaledresolution.getScaleFactor(), 300 * scaledresolution.getScaleFactor()); GL11.glTranslatef(-0.75F, -0.1F, 0.0F);
Scaled Résolution est la taille de la résolution qui nous sera utile pour la taille du modèle, pas pour lui définir une taille mais pour la texture
glViewport sert à générer un “cube invisible” pour permettre au modèle d’apparaître
glTranslatef lui nous sert à centrer le modèle dans le “cube invisible” qui permet au modèle de se… matérialiser ? en 3D
Modifiez ses valeurs et vous verrez la taille, à peu près, du cubeCe qui suit va être expliqué par des commentaires java
//Ici ça gère les dimensions du modèle, largeur, hauteur, longueur //Il est préconfiguré pour un cube ! //S'cadeau c'est bonus ! //A modifier si vous voulez faire le rendu d'un mob ! GL11.glScalef(0.66F, 0.85F, 0.66F); //Permet d'afficher le modèle sous un certain angle Project.gluPerspective(90.599998F, 1.333333F, 9.0F, 180.0F); //Distance de vue (FOV) du modèle dans le "cube invisible" //Essayez 2.0F et vous verrez il sort de l'ecran, c'est de la vraie 3D ! //Non c'est une blague, mais ça zoom pas mal ! float f1 = 1.0F; //A ne pas modifier c'est comme le 5889 d'en haut, et à ce stade j'ai l'impression que c'est comme des ID GL11.glMatrixMode(5888); GL11.glLoadIdentity(); //Pour une jolie luminosité du modèle RenderHelper.enableStandardItemLighting(); //C'est subtile, ça permet de bouger la vue 2D du modèle dans le "cube invisible" si vous modifiez -16.0F //Par -17 ou -18 on le voit sortir par l'arrière du "cube invisible" GL11.glTranslatef(0.0F, -3.6F, -16.0F); //Le FOV GL11.glScalef(f1, f1, f1); //Définit les proportions du modèle un peu comme.... //GL11.glScalef(0.66F, 0.85F, 0.66F); //Mais cette fois si c'est grossier GL11.glScalef(4.0F, 4.0F, 4.0F); //Alors là c'est un peu spécial et marrant ! //Ça permet de rotate le modèle //Mais si vous mettez 20.0F différent de la même méthode un peu plus bas //On peu étirer le modèle, le déformer ! GL11.glRotatef(20.0F, -1.0F, 0.0F, 0.0F); //Applique la texture au Modèle this.mc.getTextureManager().bindTexture(campfireTexture); //Expliqué un peu plus haut GL11.glRotatef(20.0F, 1.0F, 0.0F, 0.0F); //La profondeur du "cube invisible" mais je ne suis pas sûr ! float f3 = this.field_74208_u + (this.field_74209_t - this.field_74208_u) * par1; GL11.glTranslatef((1.0F - f3) * 0.2F, (1.0F - f3) * 0.1F, (1.0F - f3) * 0.25F); //Donne de l'épaisseur au modèle, à vous de voir ! GL11.glScalef(1.1F, 1.1F, 0.5F); //Fixe la texture sur le bloc, mob ... //Empêche la texture de changer de position, de pivoter sur elle même GL11.glRotatef(-(1.0F - f3) * 90.0F - 90.0F, 0.0F, 1.0F, 0.0F); //Et une tête à l'envers, UNE ! //Fait pivoter le modèle GL11.glRotatef(180.0F, 1.0F, 0.0F, 0.0F);
Voilà c’est presque fini ! Je suis arrivé à ce résultat après 1 / 2 heures de test avec l’outils débug d’Éclipse !
A la suite on va rajouter des fonctions OpenGL et l’appel du render() qui ce trouve dans la classe du modèle 3D, ici ModelTROISD
Je ne les décris pas elles ont les mêmes nom que certaines fonctions vues plus hautGL11.glEnable(32826); //Appel de la fonction render() du ModelTROISD modelTroisD.render(0.0625F); GL11.glDisable(32826); RenderHelper.disableStandardItemLighting(); GL11.glMatrixMode(5889); GL11.glViewport(0, 0, this.mc.displayWidth, this.mc.displayHeight); GL11.glPopMatrix(); GL11.glMatrixMode(5888); GL11.glPopMatrix(); //Désactive la luminosité du rendu RenderHelper.disableStandardItemLighting();
A ce stade vous allez avoir des erreurs sur les fields_xxx
il faut leur créer une méthode que nous ajouterons en dessous de la texture du modèle 3D
public float field_74209_t; public float field_74208_u;
Si vous trouvez comme moi leur nom un peu nul modifiez le ! Mettez ce que vous voulez, mais respectez la convention Java, Minuscule au premier mot puis Majuscule au mot(s) suivant(s)
Checkpoint 2 :
En ce moment votre classe doit ressembler à ça:
package tuto.modeletroisD.gui; //RAPPEL ! //N'oubliez pas les imports ! //CTRL + MAJ + O @SideOnly(Side.CLIENT) public class GuiModeleTROISD extends GuiScreen { private int updateCounter; private static ModelTROISD modeleTROISD = new ModelTROISD(); public static final ResourceLocation modeleTROISDTexture= new ResourceLocation("modid:" + "textures/vers/le/modele3D.png"); public float field_74209_t; public float field_74208_u; /** * Adds the buttons (and other controls) to the screen in question. */ public void initGui() { } /** * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e). */ protected void actionPerformed(GuiButton par1GuiButton) {} /** * Called from the main game loop to update the screen. */ public void updateScreen() { super.updateScreen(); ++this.updateCounter; } /** * Draws the screen and all the components in it. */ public void drawScreen(int par1, int par2, float par3) { } public void modeleTROISD(int par1, int par2, float par3) { GL11.glPushMatrix(); GL11.glScalef(1.0F, 1.0F, 1.0F); GL11.glColor3f(1.0F, 1.0F, 1.0F); drawModeleTROISD(par1, par2, par3); GL11.glPopMatrix(); } public void drawModeleTROISD(int par0, int par1, float par2) { GL11.glPushMatrix(); GL11.glMatrixMode(5889); GL11.glPushMatrix(); GL11.glLoadIdentity(); ScaledResolution scaledresolution = new ScaledResolution(this.mc.gameSettings, this.mc.displayWidth, this.mc.displayHeight); GL11.glViewport((scaledresolution.getScaledWidth() - 140) / 2 * scaledresolution.getScaleFactor(), (scaledresolution.getScaledHeight() - 140) / 2 * scaledresolution.getScaleFactor(), 512 * scaledresolution.getScaleFactor(), 300 * scaledresolution.getScaleFactor()); GL11.glTranslatef(-0.75F, -0.1F, 0.0F); GL11.glScalef(0.66F, 0.85F, 0.66F); Project.gluPerspective(90.599998F, 1.333333F, 9.0F, 180.0F); float f1 = 1.0F; GL11.glMatrixMode(5888); GL11.glLoadIdentity(); RenderHelper.enableStandardItemLighting(); GL11.glTranslatef(0.0F, -3.6F, -16.0F); GL11.glScalef(f1, f1, f1); float f2 = 5.0F; GL11.glScalef(4.0F, 4.0F, 4.0F); GL11.glRotatef(20.0F, -1.0F, 0.0F, 0.0F); this.mc.getTextureManager().bindTexture(campfireTexture); GL11.glRotatef(20.0F, 1.0F, 0.0F, 0.0F); float f3 = this.field_74208_u + (this.field_74209_t - this.field_74208_u) * par1; GL11.glTranslatef((1.0F - f3) * 0.2F, (1.0F - f3) * 0.1F, (1.0F - f3) * 0.25F); GL11.glScalef(1.1F, 1.1F, 0.5F); GL11.glRotatef(-(1.0F - f3) * 90.0F - 90.0F, 0.0F, 1.0F, 0.0F); GL11.glRotatef(180.0F, 1.0F, 0.0F, 0.0F); GL11.glEnable(32826); campfire.render(0.0625F); GL11.glDisable(32826); RenderHelper.disableStandardItemLighting(); GL11.glMatrixMode(5889); GL11.glViewport(0, 0, this.mc.displayWidth, this.mc.displayHeight); GL11.glPopMatrix(); GL11.glMatrixMode(5888); GL11.glPopMatrix(); RenderHelper.disableStandardItemLighting(); } }
Modification de la classe du modèle :
C’est tout simple !
Et c’est toujours dans le tutoriel Rendu complexe de bloc via TESR !
Je cite !
Une fois votre modèle exporté en java, il faut modifier quelques trucs dedans. Placez la classe du modèle dans votre package client puis changez la déclaration de package. Ensuite faite ctrl + shift + o pour mettre à jour les importations (prenez toujours net.minecraft.quelque chose
Tout à la fin de la classe, supprimez la fonction setRotationAngles.
Ensuite modifiez la méthode render, supprimez tous les paramètres sauf le dernier, nommez-le juste f. Modifiez ensuite le paramètre des Shape.render en f. Exemple :public void render(float f) { Shape1.render(f); Shape2.render(f); Shape3.render(f); Shape4.render(f); Shape5.render(f); Shape6.render(f); }
Ce sera la même chose pour un mob !
(Peut-être une suite pour animer un mob dans un GUI ???)Afficher tout ça en jeu :
Nous avons presque fini il nous manque plus qu’à afficher tout ça en jeu !
Moi je me sert de KeyBinding pour faire ça mais à vous d’adapter l’ouverture du GUI !
Pour que tout fonctionne bien il faut ajouter deux bout de code à la fonction drawScreen(), juste avant super.drawScreen !
Ça (pour l’esthétisme):
this.drawDefaultBackground();
Affichera un fond noir mais transparent
Et ça:
this.drawModeleTROISD(par1, par2, par3);
Pour pouvoir afficher le modèle 3D ENFIN !
Bonus
Rotation du Modèle dans un GUI:
A ajouter:
public int rotation; public int speedRotation = 1;
En dessous de:
public static final ResourceLocation campfireTexture = new ResourceLocation("viruz:mob/zombies/zombie0.png");
A ajouter au début de la fonction drawModeleTROISD()
this.rotation+= speedRotation; if(this.rotation> 360) { this.rotation= 0; }
Ceci
GL11.glRotatef(this.rotation, 0.0F, 1.0F, 0.0F);
Entre
GL11.glScalef(1.1F, 1.1F, 0.5F);
Et
GL11.glRotatef(-(1.0F - f3) * 90.0F - 90.0F, 0.0F, 1.0F, 0.0F);
Sur le Menu Principal:
Il faut faire la même chose !
Résultat
Avec la rotation (pas de vidéo mais on voit que ça tourne)
Sans Rotation
Quelques Variantes:
Avec 2 modèles 3D
Avec un Mob:
Il en existe plein d’autres ! À vous de jouer !
Crédits
Rédaction :
- ZeAmateis
Aide à la traduction des fonctions OpenGL :
- jglrxavpok
Correction :
Ce tutoriel de Minecraft Forge France est mis à disposition selon les termes de la licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International -
Très bon tutoriel bravo!
-
J’ai regardé à la volé car j’ai pas trop le temps, mais ça m’a l’air pas mal
Je vais m’occuper de tous les tutoriels dès que je rentres de vacance, ça va faire du boulot x).Ah, j’ai retiré le message en haut aussi.
-
Oui le message était une blague ^^
-
Merci Fine de la correction !
-
Je vais essayer d’expliquer toutes les fonctions d’OpenGL utilisées dans mon prochain post sur ce topic
-
Ok j’allais justement rajouter au topic si tu pouvais filer un coup de main ^^
-
GL11.glPushMatrix(); GL11.glMatrixMode(5889); GL11.glPushMatrix(); GL11.glLoadIdentity();
glPushMatrix() –> sauvegarde la matrice courrante.
glMatrixMode(5889) --> traduisible par glMatrixMode(GL_PROJECTION), mets en place la matrice pour la projection (“2D”)
GL11.glPushMatrix(); --> Idem
GL11.glLoadIdentity(); --> charge une matrice “vide”ScaledResolution scaledresolution = new ScaledResolution(this.mc.gameSettings, this.mc.displayWidth, this.mc.displayHeight); GL11.glViewport((scaledresolution.getScaledWidth() - 140) / 2 * scaledresolution.getScaleFactor(), (scaledresolution.getScaledHeight() - 140) / 2 * scaledresolution.getScaleFactor(), 512 * scaledresolution.getScaleFactor(), 300 * scaledresolution.getScaleFactor()); GL11.glTranslatef(-0.75F, -0.1F, 0.0F);
glViewport(…) --> définit un rectangle où l’on va dessiner notre modèle.
glTranslatef(x,y,z) --> déplace la vue courrante vers x,y,zProject.gluPerspective(90.599998F, 1.333333F, 9.0F, 180.0F);
Dans l’ordre:
Fov --> L’angle de vue en degrés, plus la valeur est grande, plus vous verrez de choses à l’écran
Aspect ratio --> Ratio de l’aspect: le plus souvent largeur/hauteur, ici 4:3
zNear --> la distance minimale entre la caméra et l’objet pour être visible.
zFar --> la distance maximale entre la caméra et l’objet pour être visible.GL11.glMatrixMode(5888);
pareil que tout à l’heure sauf que 5888 peut être remplacé par GL_MODELVIEW (on repasse en 3D)
glDisable(32826) --> 32826 est en faite GL12.GL_RESCALE_NORMAL
On désactive le scaling “classique” (alors, pourquoi, là j’ai aucune idée) -
Je modifie donc le topic en conséquence mais ce soir ^^