using UnityEngine; namespace MyInfoMate.Vr.Scene { /// /// Conversion glTF → Unity. Le seul endroit du projet où elle existe. /// /// glTF est en main droite, Y-up, unités en mètres. Unity est en main /// gauche. Passer de l'un à l'autre demande d'inverser un axe horizontal. /// /// Le décor, lui, est converti par glTFast à l'import. Les coordonnées du /// manifeste, elles, ne passent par aucun importeur. Si les deux conversions /// ne sont pas la même, les objets placés sont en miroir par rapport au décor /// — et c'est invisible sur une scène symétrique, donc découvert tard. /// /// D'où : la valeur par défaut est celle que documente /// glTFast, mais elle se vérifie avec calibration.glb (voir /// ), elle ne se suppose pas. Si le test montre /// un miroir, c'est cette seule ligne qui change. /// public static class GltfSpace { public enum Convention { NegateX, NegateZ } public static Convention Axis = Convention.NegateX; public static Vector3 ToUnity(Vector3 p) => Axis == Convention.NegateX ? new Vector3(-p.x, p.y, p.z) : new Vector3(p.x, p.y, -p.z); /// /// Une réflexion inverse le sens des rotations : l'axe est réfléchi et /// l'angle change de signe. Sur un quaternion, ça revient à inverser le signe /// des deux composantes que la réflexion ne touche pas. /// public static Quaternion ToUnity(Quaternion q) => Axis == Convention.NegateX ? new Quaternion(q.x, -q.y, -q.z, q.w) : new Quaternion(-q.x, -q.y, q.z, q.w); /// Les coordonnées du manifeste arrivent en tableaux JSON. public static Vector3 Position(float[] v) => ToUnity(new Vector3(v[0], v[1], v[2])); public static Quaternion Rotation(float[] q) => ToUnity(new Quaternion(q[0], q[1], q[2], q[3])); /// L'échelle est invariante par réflexion — pas de conversion. public static Vector3 Scale(float[] s) => new Vector3(s[0], s[1], s[2]); } }