Navigation

    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    1. Home
    2. jglrxavpok
    • Profile
    • Following 1
    • Followers 2
    • Topics 21
    • Posts 779
    • Best 28
    • Groups 1

    jglrxavpok

    @jglrxavpok

    Modérateurs

    Bannière: extrait d'un dessin de ma copine. Allez voir son profil DeviantArt! https://papaslender.deviantart.com/

    96
    Reputation
    2552
    Profile views
    779
    Posts
    2
    Followers
    1
    Following
    Joined Last Online
    Website steamcommunity.com/id/jglrxavpok Location France

    jglrxavpok Follow
    Modérateurs

    Best posts made by jglrxavpok

    • RE: GLUtils, ou comment faire des modèles 3D facilement

      Tu fais chercher le modèle dans /assets/obj/ alors qu’il est dans /assets/tonmod/obj/, à corriger

      posted in Autres
      jglrxavpok
      jglrxavpok
    • RE: Vos plus beaux fails

      Nous pouvons observer un phénomène rare mais magnifique de Mère Nature: un vol de textures manquantes.
      Ces oiseaux gracieux volent en groupe pour migrer vers des pays plus chauds avant l’arrivée de l’hiver.

      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: Modifier le menu principal

      Je pense qu’il ne faut pas faire une classe fille de GuiMainMenu (extends GuiMainMenu) mais uniquement de GuiScreen.
      Ça devrait régler (du moins en partie) le problème.

      posted in 1.7.x
      jglrxavpok
      jglrxavpok
    • RE: Load .obj

      En passant, les multiples textures sont gérées 😄



      posted in Anciennes versions
      jglrxavpok
      jglrxavpok
    • RE: Load .obj

      Pour des codes d’aide pour OpenGL: https://github.com/jglrxavpok/jglrxavpok_lwjgl_utils
      Pour UNIQUEMENT le .jar pour charger les .obj: https://github.com/jglrxavpok/jglrxavpok_lwjgl_utils/raw/master/glutils.jar

      Charger un .obj:

      model = new GLUtils("/cheminVersLeFichierObj");
      

      Dessiner un .obj:

      model.render();
      
      posted in Anciennes versions
      jglrxavpok
      jglrxavpok
    • RE: [Résolu] Redimensionnement d'image

      Sinon, avec le code:

      BufferedImage img = tonImage;
      Image newImage = img.getScaledInstance(newWidth, newHeight, BufferedImage.SCALE_FAST);
      
      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: Problème Timer et Tp

      Le problème est finalement résolu!

      private ChunkCoordinates findClosestBlockOfBiome(Entity e, BiomeGenBase b, double radius)
      {
      World w = e.worldObj;
      double min = Double.POSITIVE_INFINITY;
      ChunkCoordinates current = null;
      for(double x = -radius;x<=radius;x+=0.5)
      {
      for(double z = -radius;z<=radius;z+=0.5)
      {
      double dist = Math.sqrt(Math.pow((e.posX-(int)Math.floor(x+e.posX)),2)+Math.pow((e.posZ-(int)Math.floor(z+e.posZ)),2));
      if(w.getBiomeGenForCoords((int)Math.floor(x+e.posX), (int)Math.floor(z+e.posZ)) == b && dist <= radius && min > dist)
      {
      min = dist;
      current = new ChunkCoordinates((int)Math.floor(x+e.posX), 0, (int)Math.floor(z+e.posZ));
      }
      }
      }
      return current;
      }
      
      posted in 1.7.x
      jglrxavpok
      jglrxavpok
    • RE: [Rémunéré] Moddeur

      Comme dit ici:
      http://minecraftforgefrance.fr/showthread.php?tid=745&pid=8265#pid8265

      Tu pourrais au moins essayer de présenter mieux ton serveur, et ici, nous ne sommes pas sur un marché aux moddeurs.
      Essaie de te faire une place dans la communauté avant de recruter.

      posted in Recrutement
      jglrxavpok
      jglrxavpok
    • RE: Uncrafting Table Mod - Décrafting pour tous les items

      Le mod a été mis à jour pour la 1.7.2!

      Changelog:

      • Si vous donnez plus d’items que nécessaire, ces items seront eux aussi décraftés.
      • Passage à la 1.7
      posted in Mods complet
      jglrxavpok
      jglrxavpok
    • RE: Créer un modèle avec techne et l'appliquer à un mob

      Ton ModelTest est bien une classe avec “extends ModelBiped” ?
      Sinon, au choix:

      1. Fais extends ton ModelTest de ModelBiped si tu veux un mob humanoïde. (je ne le recommanderai pas pour avoir 100% de contrôle)

      2. Change ton constructeur pour accepter ModelBase ou ModelMobTest et non plus ModelBiped (surement le plus logique à faire)

      posted in Les entités
      jglrxavpok
      jglrxavpok

    Latest posts made by jglrxavpok

    • Optimiser (Partie 1): Les opérations lourdes

      Sommaire

      • Introduction
      • La création d’objets
      • Moins d’objets
      • Réutilisation des objets

      Introduction

      Bonjour chers lecteurs,

      Votre code est-il lent ? Vous voulez l’optimiser? Vous êtes arrivés à bon port! Découvrez l’Optimisator2000!

      -Equipe Marketing de Minecraft Forge France

      Ce tutoriel, qui sera découpé en plusieurs parties pour des questions de lisibilité et de simplicité, va vous expliquer certaines méthodes générales pour optimiser votre code.

      Attention: Toutes les optimisations ne sont pas forcément bonnes à faire et je vous conseille de faire fonctionner votre mod avant de penser à l’optimisation!

      La création d’objets

      Une des premières raisons des ralentissements sur Minecraft est le Ramasse-Miettes de la JVM (Garbage Collector).
      Le Ramasse-Miettes est, pour simplifier, un module de la JVM qui s’occupe de nettoyer la mémoire qui n’est plus utilisable (inaccessible pour votre code).

      Exemple:

      void f() {
          uneAutreFonction();
          // l'objet n'est plus accessible, donc la mémoire qu'il utilise est candidate pour être réutilisée
      }
      
      void uneAutreFonction() {
          Object o = new Object(); // une portion de la mémoire disponible est allouée pour cet objet
          System.out.println(o);
      }
      

      Cependant, le Ramasse-Miettes n’est pas parfait: il ne s’active que de temps en temps, et le plus souvent en urgence parce qu’il n’y a plus de place (pour MC).
      Ces activations à répétitions ont un coût: le Ramasse-Miettes doit réorganiser la mémoire utilisée, et cela prend un peu de temps.

      Comment éviter au Ramasse-Miettes tout ce travail?
      Il existe plusieurs façons de gérer le problème, qui dépendent de vos préférences, de si on peut réutiliser l’objet et plein d’autres paramètres dépendants du contexte. Je vais vous en présenter quelque-unes.

      Moins d’objets

      Ne pas créer d’objets quand vous n’avez pas besoin.
      Une proposition vague, certes, mais c’est la base.

      Exemple (avec la librairie JOML)

      Vector3f myVec = …;
      myVec.add(Vector3f(1f, 45f, 42f));
      

      peut être réécrit en:

      Vector3f myVec = ...;
      myVec.add(1f, 45f, 42f);
      

      Créez certains objets qu’une seule fois!
      Lorsqu’un objet n’est utilisé qu’à l’intérieur d’une fonction, réfléchissez à s’il est possible d’en faire une variable externe à la fonction.
      Exemple avec encore JOML

      void tourneMonVecteur(Vector3f vec) {
          Matrix3f myMat = new Matrix3f();
          myMat.identity().rotate((float)Math.PI, 1f, 0f, 0f);
          myMat.transform(vec);
      }
      

      peut se réécrire:

      private Matrix3f myMat = new Matrix3f().identity().rotate((float)Math.PI, 1f, 0f, 0f); // on profite des mécanismes de chaînage de JOML ici
      void tourneMonVecteur(Vector3f vec) {
          myMat.transform(vec);
      }
      

      Lorsque l’objet doit être configuré en plus d’être instancié, pensez aux constructeurs et au bloc ‘static’ (lorsque votre fonction est statique)

      Reprise de l’exemple précédent

      private Matrix3f myMat = new Matrix3f();
      
      public MaClasse() {
          myMat.identity();
          myMat.rotate((float)Math.PI, 1f, 0f, 0f);
      }
      
      void tourneMonVecteur(Vector3f vec) {
          myMat.transform(vec);
      }
      

      ou

      private static Matrix3f myMat = new Matrix3f();
      
      // Exécuté lors du chargement de la classe par la JVM
      static {
          myMat.identity();
          myMat.rotate((float)Math.PI, 1f, 0f, 0f);
      }
      
      static void tourneMonVecteur(Vector3f vec) {
          myMat.transform(vec);
      }
      

      Utilisez les singletons!
      Lorsque possible, utilisez le pattern Singleton: créez un objet dont l’instance sera la seule utilisée. Je vais simplement vous donner la structure la plus utilisée en Java:

      public class Singleton {
      
          private static Singleton instance;
      
          private Singleton() {
          }
      
          public static Singleton getInstance() {
              if(instance == null)
                  instance = new Singleton();
              return instance;
          }
      }
      

      Vous pouvez l’utiliser en appelant ‘getInstance’ (c’est ce pattern qu’utilise Minecraft pour la classe… “Minecraft”)

      La réutilisation d’objets

      Une autre option est de réutiliser les mêmes objets. Imaginons que vous voulez faire une arme à feu à l’aide de projectiles, vous allez sûrement avoir besoin de créer un grand nombre de projectiles si votre arme a une cadence élevée. La méthode naïve consiste à créer un objet à chaque tir:

      public class MonProjectile {
      
          private float tempsVivant;
          private float maxTempsVivant = 42f;
      
          public void onUpdate(float dt) {
          // …
              tempsVivant += dt; // vous pouvez aussi utiliser des ticks
              if(tempsVivant > maxTempsVivant) {
                  this.meurt();
              }
          }
      
          public void meurt() {
              // ...
          }
      
          public void prepare() {
              // ...
          }
      
          public void spawn() {
              // ...
          }
      }
      
      // ...
      
      public class MaSuperArme {
      
          public void tire() {
              MonProjectile projectile = new MonProjectile();
              projectile.prepare();
              projectile.spawn();
          }
      }
      

      Vous remarquerez sans doute que l’on va créer un nombre considérable d’objets dont on n’aura plus besoin quelques secondes après. Une solution est de remettre à zéro les objets lors qu’ils devraient être détruits et de les garder de côté pour les réutiliser et la méthode ‘tire’ ressemblerait à ceci:

      public void tire() {
          MonProjectile projectile = recycle(); // c'est là que la magie va se passer!
          projectile.prepare();
          projectile.spawn();
      }
      

      ❓ Mais comment implémenter cette méthode ‘recycle’, me direz-vous ?
      ❗ Et bien on va utiliser ce qui s’appelle une piscine (Pool en anglais)!

      Il existe plusieurs façons de les implémenter, et j’ai choisi de vous présenter une version simple avec une liste:

      /**
      * License: Do whatever you want with this. -Xavier 'jglrxavpok' Niochaut
      */
      
      import java.util.LinkedList;
      import java.util.List;
      
      public abstract class Pool<T>{
      
          // On va utiliser une LinkedList parce que l'on va faire beaucoup d'ajouts et de retraits dans cette liste
          private List<T>ready = new LinkedList<>();
      
          /**
          * 'Libère' un objet ie. le prépare pour sa réutilisation plus tard lors d'un appel à {@link #get()} et le
          * rajoute à cette piscine
          * @param object L'objet à réutiliser plus tard
          */
          public void free(T object) {
              ready.add(object);
          }
      
          /**
          * Renvoie un objet qui a été soit:
          *
          * - recyclé
          * - créé car il n'y avait plus d'objets dans la piscine
          * @return l'objet recyclé ou créé
          */
          public T get() {
              if(ready.isEmpty()) {
                  return create();
              }
              return ready.remove(0); // on retire le premier élément de la liste
          }
      
          /**
          * Crée un nouvel objet de type 'T' au cas où il n'y en aurait plus de libre. Ne le rajoute pas à la piscine.
          * @return l'object créé
          */
          protected abstract T create();
          }
      }
      

      Créons notre piscine pour les projectiles:

      public class ProjectilePool extends Pool <monprojectile>{
      
          @Override
          protected MonProjectile create() {
              return new MonProjectile();
          }
      }
      

      Et utilisons-la:

      public class MaSuperArme {
      
          private ProjectilePool projectilePool = new ProjectilePool();
      
          public void tire() {
              MonProjectile projectile = recycle();
              projectile.prepare();
              projectile.spawn();
          }
      
          public MonProjectile recycle() {
              return projectilePool.get();
          }
      }
      
      public class MonProjectile {
      
          private float tempsVivant;
          private float maxTempsVivant = 42f;
          private ProjectilePool pool;
      
          public void onUpdate(float dt) {
              // ...
              tempsVivant += dt; // vous pouvez aussi utiliser des ticks
              if(tempsVivant > maxTempsVivant) {
                  this.meurt();
              }
          }
      
          public void meurt() {
              pool.free(this);
          }
      
          public void prepare(ProjectilePool pool) {
              // ...
              this.pool = pool;
          }
      
          public void spawn() {
              // ...
          }
      }
      

      Et voilà! Vos projectiles sont maintenant recyclés!

      Attention! N’oubliez pas de réinitialiser tous les propriétés (position, vitesse, vie, etc.) de vos objets avant de les utiliser!

      Et voilà pour ce petit tutoriel sur la base gestion de la mémoire utilisée par votre mod, j’espère qu’il vous aura plu!

      posted in Autres
      jglrxavpok
      jglrxavpok
    • RE: Votre jeu indé du moment

      En ce moment, je joue pas mal à

      • Steredenn, un shooter fait par un studio breton
      • Shenzhen I/O, un jeu basé sur la programmation et l’électronique
      • TIS-100, un jeu basé aussi sur la programmation (même développeur), sur un ordinateur mystérieux…
      • FTL: Faster Than Light, moi aussi j’aime beaucoup son style mais on ne le présente plus 😉
      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • Un remplaçant de Paulscode's SoundSystem pour LWJGL 3: Audiokode

      #Introduction(Introduction)
      Depuis la sortie de LWJGL 3.x, la (célèbre ?) librairie de Paulscode, 3DSoundSystem, n’est plus utilisable et elle n’a pas été mise à jour.
      La solution la plus adoptée a donc été d’écrire son propre code pour OpenAL et le chargement de musiques/bruitages. Je vous propose de remédier à cela!

      #Installation(Installation)
      Pour le moment, le seul moment est copier les sources et de compiler la librairie soit-même.

      Cependant, si vous avez Git d’installé et que vous utilisez Gradle, vous pouvez ajouter ceci dans .gitmodules (rajoutez le dans votre dossier racine si vous n’en n’avez pas):

      [submodule "Audiokode"]
      path = Audiokode
      url = https://github.com/jglrxavpok/Audiokode.git
      

      Vous pouvez aussi faire cette commande dans votre dossier racine:

      git submodule add https://github.com/jglrxavpok/Audiokode.git
      

      Cela téléchargera en plus directement le projet (et modifies le fichier .gitmodules en conséquence).

      Ensuite, une fois ceci fait, ajoutez ceci dans votre settings.gradle (à créer si besoin):

      include 'Audiokode'
      

      Et dans votre fichier build.gradle:

      // …
      dependencies {
      // ...
      compile project(':Audiokode')
      // ...
      }
      // ....
      
      

      Un petit refresh des dépendances avec Gradle, et vous êtes prêts!

      #Utilisation(Utilisation)
      Initialisation du système:

      // Initialisation
      SoundEngine engine = new SoundEngine();
      engine.initWithDefaultOpenAL();
      

      Exemple pour jouer une musique:

      // Une musique de fond
      Source source = engine.backgroundMusic("TestWav", false);
      source.play();
      source.setGain(0.15f); // contrôler le volume
      

      :::

      engine.quickplayBackgroundMusic("TestWav");
      

      :::

      Attention! Si vous n’utilisez pas ThreadedSoundEngine, vous aurez besoin d’ajouter ceci dans la boucle principale de votre jeu:

      engine.update();
      

      Cela permet à Audiokode de faire boucler les musiques, de faire bouger l’écouter, etc.

      Et voilà! Vous pouvez aussi utiliser ThreadedSoundEngine si vous voulez laisser Audiokode mettre à jour votre son tout seul dans son coin.

      Lien Github

      posted in Vos autres créations
      jglrxavpok
      jglrxavpok
    • RE: Indicateur de chat

      Il risque d’y avoir un problème vu comment c’est parti.

      Minecraft.getMinecraft().ingameGUI.getChatGUI().getChatOpen()
      ``` ne permet de savoir que si le client sur lequel le mod tourne a son tchat ouvert. Il faudrait envoyer un message (via des packets) au serveur pour lui dire que le joueur est en train d'écrire, puis de retransmettre cette information à tous les clients connectés, et enfin d'afficher la bulle uniquement si ton client a reçu l'information que le joueur J est bien en train d'écrire.
      
      PS: N'hésite pas à poster tes retours sur le tuto OpenGL dans ses commentaires, il manque cruellement de retours ce tuto.
      
      Edit: J'ai lu trop en diagonale et quelqu'un d'autre a déjà soulevé ce problème, mais j'espère que mon explication pourra t'aider quand même.
      posted in 1.7.x
      jglrxavpok
      jglrxavpok
    • Les bases pratiques d'OpenGL

      Sommaire

      • Introduction
      • Pré-requis
      • Commandes
        • Points importants
        • glColor: les colorations
        • glTranslate: les translations
        • glRotate: les rotations
        • glScale: les homothéties
        • glEnable: les capacités
      • Points avancés
        • Utiliser plusieurs textures en même temps
        • Sélectionner un rectangle de rendu
      • Bonus
        • Utiliser le VertexBuffer pour choisir comment dessiner
        • Utiliser le stencil buffer pour sélectionner une zone de rendu, peu importe la forme
      • Conclusion
      • Crédits

      Introduction

      Bonjour chers lecteurs,

      Vu les nombreuses demandes d’aide qui pourraient être réglées avec un minimum de connaissances des bases d’OpenGL, voici un petit tutoriel pratique sur les bases de cette librairie graphique.

      XOXOXO -jglrxavpok

      Le code de ce tutoriel est disponible ici.

      Le but de ce tutoriel est de vous apprendre à utiliser les bases d’OpenGL pour vous aider à faire vos mods, il n’ira donc pas dans les détails du fonctionnement de la librairie.
      Par soucis de simplicité, les diverses commandes vont être présentées pour le rendu dans un Gui mais les idées restent les mêmes dans n’importe quel contexte.

      Pré-requis

      Pour ce tutoriel, vous devez avoir suivi au moins les tutoriels suivants:

      • Installer les logiciels nécessaires au modding forge
      • Installer et configurer l’espace de travail de Forge
      • Créer la base de son mod

      Code de base et ressources([size]Code de base et ressources)

      Dans ce tutoriel nous utiliserons les deux images suivantes:


      Et voici l’arborescence associée:

      Voici maintenant les classes de base que l’on va utiliser pour le tutoriel, vous n’avez évidemment pas besoin d’avoir les mêmes, cela permet juste de suivre les modifications.

      package fr.minecraftforgefrance.tutorial;
      
      import fr.minecraftforgefrance.tutorial.client.ClientEventHandler;
      import net.minecraftforge.common.MinecraftForge;
      import net.minecraftforge.fml.common.Mod;
      import net.minecraftforge.fml.common.Mod.EventHandler;
      import net.minecraftforge.fml.common.event.FMLInitializationEvent;
      
      @Mod(modid = OpenGLPratique.MODID, version = OpenGLPratique.VERSION)
      public class OpenGLPratique
      {
          public static final String MODID = "openglpratique";
          public static final String VERSION = "1.0";
      
          @EventHandler
          public void init(FMLInitializationEvent event)
          {
              MinecraftForge.EVENT_BUS.register(new ClientEventHandler());
          }
      }
      
      
      package fr.minecraftforgefrance.tutorial.client;
      
      import fr.minecraftforgefrance.tutorial.OpenGLPratique;
      import net.minecraft.client.Minecraft;
      import net.minecraft.client.gui.ScaledResolution;
      import net.minecraft.client.gui.inventory.GuiInventory;
      import net.minecraft.client.renderer.Tessellator;
      import net.minecraft.client.renderer.VertexBuffer;
      import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
      import net.minecraft.util.ResourceLocation;
      
      import static org.lwjgl.opengl.GL11.*;
      
      /**
      * Ceci est une classe utilisée pour l'exemple et n'est probablement pas utilisable en pratique sans faire des gros changements.
      *
      * Permet de dessiner le logo de MinecraftForgeFrance et le modèle du joueur.
      */
      public class Renderer {
      
          private static final ResourceLocation opaqueLogo = new ResourceLocation(OpenGLPratique.MODID, "logo_mff128x128.png");
          private static final ResourceLocation transparentLogo = new ResourceLocation(OpenGLPratique.MODID, "transparentlogo_mff128x128.png");
          private static final int WIDTH = 128;
          private static final int HEIGHT = 128;
      
          public static void drawOpaqueSprite(ScaledResolution resolution) {
              Minecraft.getMinecraft().getTextureManager().bindTexture(opaqueLogo);
              Tessellator tessellator = Tessellator.getInstance();
              VertexBuffer buffer = tessellator.getBuffer();
              buffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
              float w = WIDTH / ((float)resolution.getScaleFactor());
              float h = HEIGHT / ((float)resolution.getScaleFactor());
              buffer.pos(0,0,0).tex(0, 0).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(0,h,0).tex(0, 1f).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(w, h,0).tex(1f, 1f).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(w,0,0).tex(1f, 0).color(1f, 1f, 1f, 1f).endVertex();
              tessellator.draw();
          }
      
          public static void drawTransparentSprite(ScaledResolution resolution) {
              Minecraft.getMinecraft().getTextureManager().bindTexture(transparentLogo);
              Tessellator tessellator = Tessellator.getInstance();
              VertexBuffer buffer = tessellator.getBuffer();
              buffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
              float w = WIDTH / ((float)resolution.getScaleFactor());
              float h = HEIGHT / ((float)resolution.getScaleFactor());
              buffer.pos(0,0,0).tex(0, 0).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(0,h,0).tex(0, 1f).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(w, h,0).tex(1f, 1f).color(1f, 1f, 1f, 1f).endVertex();
              buffer.pos(w,0,0).tex(1f, 0).color(1f, 1f, 1f, 1f).endVertex();
              tessellator.draw();
          }
      
          public static void drawModel(ScaledResolution resolution) {
              Minecraft mc = Minecraft.getMinecraft();
              GuiInventory.drawEntityOnScreen(100,100,resolution.getScaleFactor()*10, 0f, 0f, mc.player);
          }
      }
      
      

      Le gestionnaire d’événements

      package fr.minecraftforgefrance.tutorial.client;
      
      import net.minecraft.client.gui.ScaledResolution;
      import net.minecraftforge.client.event.RenderGameOverlayEvent;
      import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
      
      public class ClientEventHandler {
      
          @SubscribeEvent
          public void onGuiDrawing(RenderGameOverlayEvent.Pre event) {
              if(event.getType() == RenderGameOverlayEvent.ElementType.HOTBAR) {
                  draw(event.getResolution());
              }
          }
      
          /**
          * C'est la méthode que l'on va modifier dans ce tutoriel
          */
          private void draw(ScaledResolution resolution) {
              Renderer.drawTransparentSprite(resolution);
              Renderer.drawModel(resolution);
          }
      }
      
      

      Remarquez bien la méthode ClientEventHandler::draw(ScaledResolution), c’est ici que tout va se passer par la suite.
      Si vous lancez le jeu avec le code tel quel, vous devriez avoir quelque chose comme ceci:

      Et voilà vous êtes prêts!

      Commandes

      Premier points

      Avant de commencer à apprendre les commandes de base, il faut que je vous apprenne deux-trois choses sur la façon dont on accède à ces commandes. De plus, pour simplifier, le préfixe GL11. sera omis. C’est possible en ajoutant ceci dans les imports de la classe dans laquelle vous travaillez:

      import static org.lwjgl.opengl.GL11.*;
      

      Points importants:

      • Il est possible (au moins jusqu’à la version 1.11, incluse, de Minecraft) de remplacer les commandes d’OpenGL par des fonctions de GlStateManager, elles sont même préférables à utiliser pour le modding. (les correspondances seront explicitées dans ce tutoriel). Cependant, pour rester général, ce tutoriel utilisera les commandes d’OpenGL directement; cela vous permettra d’utiliser OpenGL en dehors de Minecraft!
      • Format d’une commande OpenGL: gl<nom de la commande><type des paramètres><f, i, b, ub, d, ou vide>(<arguments>)
      • Une commande OpenGL agit toujours sur le rendu fait après la commande. De plus certaines commandes ne remplacent pas mais ajoutent aux effets déjà présents dû à cette même commande (ce sera plus clair dans les exemples), ces fonctions seront explicitées dans ce tutoriel
      • Juste pour ce tutoriel: tous les bouts de code donnés sont considérés comme le contenu de la fonction draw() de ClientEventHandler
      • Juste pour ce tutoriel: tous les appels à la classe Renderer sont à remplacer par votre code de rendu (du genre model.render())

      Voilà, vous êtes prêts pour de vrai cette fois!

      glColor<nombre><type>: Multiplier la couleur

      Cliquez pour avoir la branche de cette partie.
      Propriétés à noter:

      • Remplace totalement la valeur précédente donnée
      • Remplaçable par GlStateManager::color

      La commande glColor permet de multiplier la couleur de rendu par des flottants, dissection avec un exemple:

      glColor3f(multiplicateurRouge, multiplicateurVert, multiplicateurBleu);
      glColor4f(multiplicateurRouge, multiplicateurVert, multiplicateurBleu, multiplicateurAlpha);
      

      Chaque couleur peut être décomposée en trois composantes rouge, vert et bleu (l’espace RGB en anglais) et cette commande permet d’agir sur chacune de ses composantes:
      chacun des termes va multiplier la composante choisie par le terme donné.

      Merci Wikipedia!

      Pour ne garder que le bleu du logo du site, on peut faire ainsi:

              glColor3f(0f, 0f, 1f);
              Renderer.drawTransparentSprite(resolution); // rendu du logo du site avec uniquement le bleu
      
      

      Et pour mettre le logo en opacité à 25%, sans bleu et ajouter le rouge et le vert à 50%:

              glColor4f(0.5f, 0.5f, 0f, 0.25f);
              Renderer.drawTransparentSprite(resolution); // rendu du logo du site à 25% d'opacité, pas de bleu, et division par 2 du rouge et du bleu
      
      

      Attention, cette méthode remplace la couleur précédente:

      glColor3f(0f, 0f, 0f);
      glColor4f(1f, 1f, 1f, 1f);
      Renderer.drawTransparentSprite(resolution); // rendu du logo en couleurs normales!
      

      Ici la couleur est normale au lieu de dessiner le logo en noir!

      glTranslate<type>: faire une translation

      Cliquez pour avoir la branche de cette partie.
      Propriétés à noter:

      • Opération de transformation: on déplace le contenu
      • Des translations successives s’ajoutent!
      • Dans les Gui (à cause de la projection orthographique pour ceux qui veulent le détail), la coordonnée sur Z n’influence pas la taille de l’objet.
      • Remplaçable par GlStateManager::translate

      Avant de vous introduire à glTranslate, il faut que vous voyez glPushMatrix et glPopMatrix.
      Ces deux méthodes vous permettent de sauvegarder la transformation courante:

      • glPushMatrix: sauvegarde la transformation sur une pile de sauvegarde
      • glPopMatrix: restaure la pile en haut de la pile et la retire de cette pile

      Elles s’utilisent donc ainsi:

      glPushMatrix();
      // transformations: translations, rotations, homothéties
      Renderer.drawTransparentSprite(resolution);
      glPopMatrix();
      

      Explication de Wikipédia:
      [quote]
      informatique, une pile (en anglais stack) est une structure de données fondée sur le principe « dernier arrivé, premier sorti » (ou LIFO pour last in, first out), ce qui veut dire, qu’en général, le dernier élément ajouté à la pile sera le premier à en sortir. Le fonctionnement est similaire à celui d’une pile d’assiettes : on ajoute des assiettes sur la pile, et on les récupère dans l’ordre inverse, en commençant par la dernière ajoutée.
      [/quote]

      La commande glTranslate(x, y, z) permet de faire des translations au contenu qui va être dessiné selon les 3 axes X, Y et Z (locaux, on verra plus tard pourquoi).
      L’unité des paramètres dépend énormément du contexte, par exemple pour les blocs, l’unité sera des blocs alors que pour les Gui, ce sera (à peu près) des pixels.

      glPushMatrix();
      // transformations: translations, rotations, homothéties
      // point important: dans un Gui, la coordonnée sur Z n'influence pas la taille
      // (mais permet d'afficher du contenu devant ou derrière quelque chose, selon la valeur choisie)
      glTranslatef(100f, 30f, -1f);
      Renderer.drawModel(resolution);
      glPopMatrix();
      

      Avant le glTranslate:

      Après le glTranslate

      On peut voir que les effets s’ajoutent en décomposant selon les 3 axes, par exemple: les deux codes suivants sont équivalents

      glTranslatef(100f, 0f, 0f);
      glTranslatef(0f, 30f, 0f);
      glTranslatef(0f, 0f, -1f);
      
      glTranslatef(100f, 30f, -1f);
      

      glRotate<type>: faire une rotation

      Cliquez pour avoir la branche de cette partie.
      Propriétés à noter:

      • Opération de transformation: on déplace le contenu
      • Des rotations successives s’ajoutent!
      • L’ordre des rotations a une importante!
        *Remplaçable par GlStateManager::rotate

      La commande glRotate est assez simple: elle prend 4 paramètres qui sont:

      • L’angle de rotation, en degrés, avec les angles positifs allant dans le sens horaire. (attention, si vous utilisez des matrices de rotation plus tard, ce sera en radians et dans le sens trigonométrique)
      • La coordonnée sur l’axe (Ox) de l’axe de rotation
      • La coordonnée sur l’axe (Oy) de l’axe de rotation
      • La coordonnée sur l’axe (Oz) de l’axe de rotation

      Un petit schéma:

      Exemple:
      Essayez ceci (explication après la vidéo):

      glPushMatrix();
      glTranslatef(100f, 100f, 0f);
      glRotatef(Minecraft.getSystemTime()*.125f, 0f, 0f, 1f);
      glTranslatef(-64f/resolution.getScaleFactor(), -64f/resolution.getScaleFactor(), 0f);
      Renderer.drawTransparentSprite(resolution);
      glPopMatrix();
      

      Vous voudriez avoir quelque chose de similaire à ceci: [video]https://youtu.be/UkAMfLfvIzY[/video]

      Dissection du code!

      glTranslatef(100f, 100f, 0f);
      

      On déplace notre contenu vers le centre (à peu près).

      glRotatef(Minecraft.getSystemTime()*.125f, 0f, 0f, 1f);
      

      Cette commande effectue une rotation d’un angle de Minecraft.getSystemTime().125f* (cela permet de faire un petit effet d’animation) autour de l’axe Z.

      glTranslatef(-64f/resolution.getScaleFactor(), -64f/resolution.getScaleFactor(), 0f); // on divise par le facteur de résolution pour faire des positions au pixel près 
      

      Alors c’est cette ligne qui apporte quelque chose d’important. Si on la retire, on obtient ceci: [video]https://youtu.be/B_dvCYeH9GU[/video]

      ❓ Pourquoi ça a changé ?
      ❗ Il s’avère que l’ordre des transformations importe beaucoup! En effet, cette ligne permet en quelque sorte de définir un point d’origine sur le sprite pour la rotation.

      Un petit schéma pour plus de détails:

      La rotation change les axes X,Y,Z locaux et la dernière translation (en rouge) est faite dans la nouvelle base (représentée en rose). La rotation se fait donc à partir du point spécifié (et on se retrouve à la position en noir).

      On peut bien évidemment faire des rotations autour des axes X et Y:

      glPushMatrix();
      glRotatef(-45f, 1f, 0f, 0f);
      glRotatef(-45f, 0f, 1f, 0f);
      Renderer.drawModel(resolution);
      glPopMatrix();
      

      Cet exemple vous donnera ceci:

      Comme dit précédemment, les rotations changent les systèmes d’axes. Ainsi le code suivant, qui inverse les rotations ne donne pas le même résultat:

      glPushMatrix();
      // inversion !
      glRotatef(-45f, 0f, 1f, 0f);
      glRotatef(-45f, 1f, 0f, 0f);
      Renderer.drawModel(resolution);
      glPopMatrix();
      

      Résultat:

      glScale<type>: homothéties et distortions

      Cliquez pour avoir la branche de cette partie.
      Propriétés à noter:

      • Opération de transformation: on déplace le contenu
      • Des homothéties successives s’ajoutent!
      • Remplaçable par GlStateManager::scale

      La commande glScale permet de faire des [infobulle=Une homothétie est une opération mathématique qui ‘allonge’ des vecteurs depuis un point de départ, un changement d’échelle, ou un redimensionnement en quelque sorte.]homothéties[/infobulle] sur chacun des trois axes. Voici les paramètres:

      • Multiplicateur sur l’axe (Ox)
      • Multiplicateur sur l’axe (Oy)
      • Multiplicateur sur l’axe (Oz)


      Merci Wikipédia encore!

      Pour chacun de ses paramètres, un multiplicateur égal à 1 équivaut à aucun changement. Une valeur entre -1 et 1 rétrécit l’objet alors qu’une valeur f telle que |f| > 1 agrandit l’objet.

      Voici un petit exemple avec le logo du forum (je n’utilise pas le modèle du joueur ici car son code de rendu fait aussi des translations, et un simple glScale ne va pas que changer sa taille, essayez par vous même):

      glPushMatrix();
      glScalef(10f, 1f, 1f);
      Renderer.drawOpaqueSprite(resolution);
      glPopMatrix();
      

      Avant:

      Après:

      Attention! Comme avec glRotate, cette commande affecte les suivantes: si vous multipliez par 0.5 sur l’axe X, votre prochaine translation sur cet axe sera elle aussi multipliée par 0.5!
      De plus, comme avec glRotate, l’ordre importe!
      Un exemple pour comparer:

      glPushMatrix();
      glTranslatef(100f, 0f, 0f);
      glScalef(2f, 1f, 1f); // On applique l'homothétie **après** la translation
      Renderer.drawOpaqueSprite(resolution);
      glPopMatrix();
      

      glPushMatrix();
      glScalef(2f, 1f, 1f); // On applique l'homothéthie **avant** la translation
      glTranslatef(100f, 0f, 0f);
      Renderer.drawOpaqueSprite(resolution);
      glPopMatrix();
      

      Il est aussi possible d’inverser des modèles et des images grâce à cette commande! Il suffit de donner une valeur négative dans l’un des paramètres:

              GlStateManager.disableCull(); // necessaire pour que ce rendu ('draw opaque sprite') fonctionne, plus d'infos plus loin
              glPushMatrix();
      
              // l'homothétie se fait depuis le point (0,0) et on décale l'image pour qu'elle apparaisse à l'écran
              // N'hésitez pas à mettre 10f sur l'axe Y pour que mieux comprendre
              glTranslatef(100f, 128f/resolution.getScaleFactor(), 0f);
              glScalef(1f, -1f, 1f); // On applique l'homothéthie **avant** la translation
              Renderer.drawOpaqueSprite(resolution);
              glPopMatrix();
              GlStateManager.enableCull(); // necessaire pour que ce rendu ('draw opaque sprite') fonctionne, plus d'infos plus loin
      
      

      glEnable: activer vos capacités!

      Propriétés à noter:

      • Change l’état d’OpenGL, pensez toujours à annuler des changements après votre rendu!
      • Vous pouvez retrouver une version pour une bonne partie des capacités dans GlStateManager.
      • Parfois remplaçable par GlStateManager::enable<capacité> ou GlStateManager::disable<capacité>

      D’inverse glDisable, la commande glEnable prend un unique paramètre: la capacité à activer (ou à desactiver).
      La liste de toutes les capacités possible est assez longue et il n’y aurait pas d’intérêt à tout expliquer ici.
      Vous pouvez cliquer sur ce lien si vous voulez vraiment la liste complète.

      En voici quelques unes qui pourraient vous être utile:

      • GL_SCISSOR_TEST: Permet de sélectionner la zone de dessin, une partie de ce tutoriel y est entièrement dédié.
      • GL_DEPTH_TEST: Permet d’activer le test de profondeur: les faces les plus proches de la caméra cachent celle de derrière
      • GL_CULL_FACE: Permet de n’afficher des polygones que dans un seul sens (voir section ‘VertexBuffer’)
      • GL_BLEND: Permet d’activer le mélange des couleurs et la transparence

      Points avancés

      Avant de s’attaquer à cette partie, je vous conseille d’avoir bien compris les parties précédentes et d’avoir acquis un peu d’aisance avec OpenGL.

      Utiliser plusieurs textures

      Cliquez pour avoir la branche de cette partie.

      Pour utiliser une texture, on doit l’attacher avec glBindTexture(GL_TEXTURE_2D, <votre n° de texture>). Cependant, Minecraft propose un moyen plus simple d’attacher une texture avec des ResourceLocation:

      mc.getTextureManager().bindTexture(<la ressource>);
      

      où mc est une instance de Minecraft (Minecraft.getMinecraft()) par exemple.

      Pour utiliser plusieurs textures pour vos rendus, il faut grouper les éléments utilisant la même texture et utiliser la texture pour ce groupe.

      Exemple avec deux textures:

          private static final ResourceLocation opaqueLogo = new ResourceLocation(OpenGLPratique.MODID, "logo_mff128x128.png");
          private static final ResourceLocation transparentLogo = new ResourceLocation(OpenGLPratique.MODID, "transparentlogo_mff128x128.png");
      
          /**
              * C'est la méthode que l'on va modifier dans ce tutoriel
              */
          private void draw(ScaledResolution resolution) {
              glPushMatrix();
              Minecraft.getMinecraft().getTextureManager().bindTexture(transparentLogo); // on attache la 1ère texture
              drawRect(128, 128, resolution); // on dessine un 1er rectangle avec la texture transparente
      
              glTranslatef(100f, 100f, 0f);
              Minecraft.getMinecraft().getTextureManager().bindTexture(opaqueLogo); // on attache la 2ème texture
              drawRect(128, 128, resolution); // on dessine un 2nd rectangle avec la texture opaque
              glPopMatrix();
          }
      
          // Ne faites pas trop attention à ça, sert à dessiner un rectangle à l'écran; cette méthode sera expliquée plus tard dans le tutoriel
          private void drawRect(int width, int height, ScaledResolution resolution) {
              Tessellator tessellator = Tessellator.getInstance();
              VertexBuffer buffer = tessellator.getBuffer();
              buffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX);
              float w = width / ((float)resolution.getScaleFactor());
              float h = height / ((float)resolution.getScaleFactor());
              buffer.pos(0,0,0).tex(0, 0).endVertex();
              buffer.pos(0,h,0).tex(0, 1f).endVertex();
              buffer.pos(w, h,0).tex(1f, 1f).endVertex();
              buffer.pos(w,0,0).tex(1f, 0).endVertex();
              tessellator.draw();
          }
      
      

      Résultat:

      Le scissor test: sélectionner une zone de rendu

      Cliquez pour avoir la branche de cette partie.
      Points importants:

      • Ce système n’est pas affectée par les transformations.
      • Les coordonnées données en paramètres sont des coordonnées en pixels correspondant à un rectangle sur l’écran.
      • Pas de remplacement dans GlStateManager.

      Vous voulez afficher votre contenu sur l’écran mais le garder dans un rectangle précis sur l’écran ?
      Le scissor test vous permet de faire exactement ceci.
      Il s’utilise ainsi:

              glEnable(GL_SCISSOR_TEST);
              glScissor(<x>,<y>, <largeur>,<hauteur>); // attention! Pour l'axe Y, le 0 est en **bas** de l'écran!
              // rendu
              glDisable(GL_SCISSOR_TEST);
      
      

      Un petit schéma:

              glEnable(GL_SCISSOR_TEST);
              glScissor(32,Minecraft.getMinecraft().displayHeight-128, 64,64); // attention! Pour l'axe Y, le 0 est en **bas** de l'écran!
              Renderer.drawOpaqueSprite(resolution);
              glDisable(GL_SCISSOR_TEST);
      
      

      Résultat:

      Bonus

      Quelques informations bonus pour approfondir vos connaissances.

      Le Vertex Buffer: prenez le pouvoir!

      Cliquez pour avoir la branche de cette partie.

      Précédemment dans ce tutoriel, on se basait soit sur la classe magique Renderer ou Gui pour le rendu; et si on choisissait nous-même comment on dessine notre contenu à l’écran?

      Dites bonjour au VertexBuffer!

      ❗ Ça en fait des membres !

      Effectivement, et il est assez facile de s’y perdre. Ce tutoriel vous permettra d’apprendre à utiliser certaines des méthodes de cette classe pour afficher du contenu.

      Accéder à une instance
      Pour utiliser le VertexBuffer, il nous faut une instance, je vous recommande de le faire ainsi:

              Tessellator tessellator = Tessellator.getInstance();
              VertexBuffer buffer = tessellator.getBuffer();
      

      Ordre des sommets
      Faites bien attention à définir vos sommets dans le sens inverse des aiguilles d’une montre, surtout lorsque vous faites un rendu 2D. En effet, Minecraft active par défaut le ‘culling’ et fais en sorte que seules les faces apparaissant dans le sens antihoraire, par rapport à la caméra, soient dessinées.
      Vous pouvez désactiver ce comportement ainsi, même si je vous le déconseille:

      glDisable(GL_CULL_FACE);
      
      begin

      Cette méthode prend deux paramètres:

      • Le mode de dessin: GL_QUADS, GL_TRIANGLES le plus généralement
      • Le format des sommets à spécifier, vous pouvez trouver ceux par défaut dans DefaultVertexFormats

      Cette méthode est à mettre obligatoirement avant chaque début de rendu!
      Le mode de dessin permet de choisir le contenu: des quads, des triangles, etc.
      Le format des sommets permet de choisir ce qui compose un sommet. Avec les différents formats disponibles dans DefaultVertexFormats, vous pouvez définir la position, les coordonnées de texture (optionnelles), la couleur du sommet (optionnelle), et un vecteur normal (optionnel).
      Petite note sur la couleur: si vous donnez une couleur pour définir vos sommets, glColor n’a plus aucun effet!

      Tessellator::draw()

      Cette méthode permet de terminer votre rendu (je vous conseille vivement de ne pas utiliser VertexBuffer::finishDrawing() si vous ne savez pas ce que vous faites).
      Exemple:

      tessellator.draw();
      

      Attention l’ordre d’utilisation des méthodes suivantes doit absolument suivre celui défini dans votre format!
      Par exemple, avec le format POSITION_TEX_COLOR, l’ordre à suivre est: pos, tex, color!

      pos

      Cette méthode prend une position (X,Y,Z) qui indique la position de votre sommet.

      tex

      Cette méthode prend une position (U,V) qui indique la coordonnée de texture:
      Un triangle utilisant les coordonnées (0;0), (0.5;0), (0.5;0.5) utilisera la partie surlignée en rose dans cet exemple:

      color

      Vous permet de definir la couleur de votre sommet, soit en RGBA avec des flottants, ou RGBA avec des entiers compris entre 0(rien) et 255(max).

      normal

      Permet de définir la normale de votre sommet.

      endVertex

      Finit la définition de votre sommet. Doit impérativement figurer à la fin de la définition d’un sommet.

      Exemple: dessiner le logo du forum
              // on récupère le buffer
              Tessellator tessellator = Tessellator.getInstance();
              VertexBuffer buffer = tessellator.getBuffer();
      
              // on commence à dessiner des quadrilatères où on donne la position et les coordonnées de textures
              buffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX);
              float w = WIDTH / ((float)resolution.getScaleFactor());
              float h = HEIGHT / ((float)resolution.getScaleFactor());
      
              // on ajoute un sommet à (0,0) avec la coordonnée (0,0) sur la texture
              buffer.pos(0,0,0).tex(0, 0).endVertex();
              buffer.pos(0,h,0).tex(0, 1f).endVertex();
              buffer.pos(w, h,0).tex(1f, 1f).endVertex();
              buffer.pos(w,0,0).tex(1f, 0).endVertex();
      
              // on dessine le contenu
              tessellator.draw();
      
      

      (on suppose que ‘WIDTH’=largeur du logo, ‘HEIGHT’=hauteur du logo, ‘opaqueLogo’=Localisation du logo)

      Le résultat, vous le connaissez:

      Un autre exemple avec l’attribut ‘COLOR’:

              // on commence à dessiner des quadrilatères où on donne la position, les coordonnées de textures et la couleur
              buffer.begin(GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
              float w = WIDTH / ((float)resolution.getScaleFactor());
              float h = HEIGHT / ((float)resolution.getScaleFactor());
      
              // on demande de ne garder que le vert de la couleur
              buffer.pos(0,0,0).tex(0, 0).color(0f, 1f, 0f, 1f).endVertex();
              buffer.pos(0,h,0).tex(0, 1f).color(0f, 1f, 0f, 1f).endVertex();
              buffer.pos(w, h,0).tex(1f, 1f).color(0f, 1f, 0f, 1f).endVertex();
              buffer.pos(w,0,0).tex(1f, 0).color(0f, 1f, 0f, 1f).endVertex();
      
              // on demande de ne garder que le rouge de la texture mais n'a aucun effet!
              glColor4f(1f, 0f, 0f, 1f);
              // on dessine le contenu
              tessellator.draw();
      
              glColor4f(1f, 1f, 1f, 1f);
      
      

      Le stencil buffer: sélectionner une zone de rendu, mais en mieux

      Cliquez pour avoir la branche de cette partie.
      Points importants:

      • Ce système peut être affecté par les transformations.
      • Les utilisations du stencil buffer sont assez variées et ce tutoriel ne donnera qu’un exemple de ce qui est possible. Je vous invite à regarder plus en détails si cela vous intéresse et voici quelques liens: Open.gl: Depth Stencils et Wiki de Khronos sur le Stencil Test
      • Pas de remplacement dans GlStateManager.

      Une utilisation possible du stencil buffer est analogue à celle du scissor test: choisir une zone de rendu. Cependant, le stencil buffer permet de choisir la forme de la zone et ne vous oblige plus à utiliser des coordonnées en pixels.
      Pour cet exemple, nous allons dessiner le logo du forum avec la forme du modèle du joueur.

              // Etape importante, permet de vérifier si le stencil buffer est activé et l'activer si ce n'est le cas
              Framebuffer framebuffer = Minecraft.getMinecraft().getFramebuffer();
              if( ! framebuffer.isStencilEnabled()) {
                  framebuffer.enableStencil();
              }
      
              glEnable(GL_STENCIL_TEST);
      
              glStencilFunc(GL_ALWAYS, 1, 0xFF); // Tous les pixels affichés vont avoir la valeur 1 dans le stencil buffer
              glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
              glStencilMask(0xFF); // On va écrire dans le stencil buffer
              glDepthMask(false); // On n'écrit plus dans le depth buffer
              glColorMask(false, false, false, false); // on désactive le rendu des couleurs
              glClear(GL_STENCIL_BUFFER_BIT); // On vide le buffer
      
              // rendu du modèle
              glPushMatrix();
              glTranslatef(-80f, -40f, 0f); // on déplace le modèle en haut à gauche
              Renderer.drawModel(resolution); // On dessine le modèle du joueur
              glPopMatrix();
      
              // rendu du logo
              // On ne dessine les pixels que si le pixel que l'on va dessiner est à une position où le stencil buffer a une valeur égale (GL_EQUAL) à 1
              glStencilFunc(GL_EQUAL, 1, 0xFF);
      
              glStencilMask(0x00); // On n'écrit plus rien au stencil buffer
              glDepthMask(true); // On réactive l'écriture vers le depth buffer
              glColorMask(true, true, true, true); // On réactive le rendu des couleurs
      
              glPushMatrix();
              glScalef(1.5f, 1.5f, 1f); // on agrandit un peu le logo pour que le modèle rentre entièremen dedans
              Renderer.drawOpaqueSprite(resolution); // On dessine notre logo
              glPopMatrix();
      
              glDisable(GL_STENCIL_TEST);
      
      

      Les explications sont dans les commentaires du code mais si vous voulez plus de détails, voici une liste d’explications des différentes fonctions utilisées:

      • glStencilFunc
      • glStencilOp
      • glStencilMask
      • glDepthMask
      • glColorMask

      Résultat:

      Conclusion

      Voilà, ce tutoriel est fini, j’espère qu’il vous a plu, et n’hésitez pas à poser des questions et à proposer des améliorations!

      Crédits

      Rédaction :
      jglrxavpok

      Correction :
      Folgansky


      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

      posted in Autres
      jglrxavpok
      jglrxavpok
    • RE: BOUM BOUM

      974 (TheFantasio)

      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: Abécédaire

      Kotlin (facile)

      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: Es-tu plus membre ou joueur ?

      Code.

      DOOM 1 ou DOOM (2016) ?

      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: BOUM BOUM

      1000

      posted in Le salon libre
      jglrxavpok
      jglrxavpok
    • RE: Problème machine

      Je pense que la question vient du fait que ton code est difficilement lisible et peu “propre”.
      Essaie de détailler un peu plus ton problème aussi.

      posted in 1.7.x
      jglrxavpok
      jglrxavpok
    Design by Woryk
    Contact / Mentions Légales / Faire un don

    MINECRAFT FORGE FRANCE © 2018

    Powered by NodeBB