2026 · actif
SiteOmega-Mod
Un mod technique intégrant un moteur de rendu de modèles OBJ personnalisés et une interface utilisateur adaptative
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) :
- ByteBuffer (Immediate Mode) : Données brutes utilisées pour un rendu dynamique via le
VertexConsumer, idéal pour l'item renderer (inventaire, sol). - VertexBuffer GPU (Fast Render) : Allocation statique envoyée directement à la VRAM. Utilisé par le
ObjArmorLayerpour 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);
}
}