Retour aux projets

2026 · actif

SiteOmega-Mod

Un mod technique intégrant un moteur de rendu de modèles OBJ personnalisés et une interface utilisateur adaptative

JavaMinecraft ForgeOpenGL/Blaze3DJOML

Overview

SiteOmega-Mod est un mod technique architecturé autour de systèmes sur mesure, notamment un moteur de rendu optimisé pour les modèles OBJ (destiné aux armures) et un framework d'interface utilisateur dynamique. Le projet exploite l'API Blaze3D de Minecraft et les Vertex Buffers (VBO) afin d'offrir des performances élevées lors du rendu de géométries complexes, contournant ainsi les limitations du format de modèle standard du jeu.

Le système de rendu de modèles OBJ (Armures)

Le cœur technique du projet réside dans le parseur ObjModelLoader et la structure de données ObjMesh. Ce pipeline permet de charger dynamiquement des modèles 3D exportés depuis un logiciel de modélisation (ex: Blender) et d'appliquer des transformations mathématiques strictes pour les conformer à l'espace de coordonnées de Minecraft.

Parsing et conversion des coordonnées

Le fichier ObjModelLoader.java lit le flux de données OBJ, extrait les sommets (v), les coordonnées de texture (vt) et les normales (vn). Une transformation spatiale est appliquée pour convertir l'espace Blender (Right-handed, Y-up) vers l'espace de modèle de Minecraft.

// Extrait de ObjModelLoader.java
if (line.startsWith("v ")) {
    float[] v = parseFloats(line.substring(2).strip(), 3);
    // Minecraft et Blender utilisent tous deux un système Right-Handed Y-up, 
    // cependant, le point d'ancrage et la direction du regard diffèrent.
    // L'inversion sur X (miroir gauche/droite) et Y (inversion verticale)
    // nécessite de stocker les sommets pré-calculés.
    globalVertices.add(new Vector3f(-v[0], -v[1], v[2]));
}

Triangulation et Winding Order

Puisque la transformation applique deux négations spatiales (-x, -y), cela génère une réflexion impaire qui inverse l'ordre d'enroulement (winding order) de tous les polygones. Pour maintenir la norme CCW (Counter-Clockwise) requise par OpenGL et éviter un culling incorrect des faces, les sommets sont réassemblés en sens inverse.

// Restauration de l'ordre d'enroulement (Winding Order)
if (count == 4) {
    // Les index sont inversés (3, 2, 1, 0) lors de la création du Quad (quadrilatère)
    // afin de restaurer le sens trigonométrique attendu par le moteur de rendu.
    mesh.addQuad(
        new Vector3f[]{positions[3], positions[2], positions[1], positions[0]}, 
        new float[][]{uvs[3], uvs[2], uvs[1], uvs[0]}, 
        new Vector3f[]{normals[3], normals[2], normals[1], normals[0]}
    );
}

Baking et optimisation mémoire (VBO)

Une fois le maillage chargé en RAM, ObjMesh.java compile (bake) les données géométriques dans deux formats optimisés pour minimiser les appels de dessin (draw calls) :

  1. ByteBuffer (Immediate Mode) : Données brutes utilisées pour un rendu dynamique via le VertexConsumer, idéal pour l'item renderer (inventaire, sol).
  2. VertexBuffer GPU (Fast Render) : Allocation statique envoyée directement à la VRAM. Utilisé par le ObjArmorLayer pour afficher l'armure sur les entités sans recalcul CPU.

Création / Utilisation d'un exemple concret : Ajout d'une armure OBJ

Pour illustrer l'ergonomie de l'API interne, voici comment un développeur peut déclarer et enregistrer un nouveau set d'armure basé sur un modèle 3D externe. Le système expose un patron de conception Builder (ArmorSetBuilder) qui résout automatiquement les textures et modèles en fonction d'une nomenclature stricte.

// Implémentation type lors de l'initialisation du mod
public static final ArmorSet CUSTOM_ARMOR = ArmorSetBuilder.of("class_d", ModArmorMaterials.CLASS_D)
    // Surcharge optionnelle du chemin si la convention par défaut n'est pas utilisée
    .obj(ResourceLocation.fromNamespaceAndPath(SiteOmega.MODID, "models/custom/armor/class_d_model.obj"))
    
    // Déclaration des pièces souhaitées (génère automatiquement les Items associés)
    .chestplate()
    .leggings()
    
    // La méthode build() relie les groupes OBJ ("BODY", "LEFT_ARM") 
    // aux slots d'équipement de Minecraft et enregistre les entités dans le Registry.
    .build(); 

Le système de composants / modules

L'architecture de l'interface graphique (UI) s'appuie sur des classes modulaires abstraites, telles que SiteOmegaScreen. Cette approche sépare la logique de gestion d'état de la logique de calcul dimensionnel.

// Extrait de SiteOmegaScreen.java montrant l'encapsulation de la logique UI
public abstract class SiteOmegaScreen extends Screen {
    protected UiMetrics ui;
    protected SiteOmegaButtons buttons;
 
    @Override
    protected final void init() {
        // La classe UiMetrics gère le scaling dynamique selon la résolution
        // évitant l'utilisation de valeurs absolues codées en dur.
        this.ui = new UiMetrics(this.width, this.height);
        this.buttons = SiteOmegaButtons.of(ui);
        
        // Hook d'initialisation pour l'implémentation concrète
        initSiteOmega(); 
    }
    
    // Délégation des événements d'interaction aux sous-composants
    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        return onSiteOmegaMouseClicked(mouseX, mouseY, button)
                || super.mouseClicked(mouseX, mouseY, button);
    }
}