Cet article est une continuation des bases des formats GLTF et GLB. Vous pouvez trouver la première partie de l'article ici . Dans la première partie, nous avons examiné avec vous pourquoi le format était initialement prévu, ainsi que les artefacts et leurs attributs du format GLTF tels que Scene, Node, Buffer, BufferView, Accessor et Mesh. Dans cet article, nous considérerons le matériau, la texture, les animations, l'habillage, l'appareil photo et terminerons également la création d'un fichier GLTF valide minimal.

Matériau et texture
Les matériaux et les textures sont inextricablement liés au maillage. Si nécessaire, le maillage peut être animé. Le matériau stocke des informations sur la façon dont le modèle sera rendu par le moteur. GLTF définit les matériaux à l'aide d'un ensemble commun de paramètres basés sur le rendu physique (PBR). Le modèle PBR vous permet de créer un affichage «physiquement correct» de l'objet dans différentes conditions d'éclairage, car le modèle d'ombrage doit fonctionner avec les propriétés de surface «physiques». Il existe plusieurs façons de décrire PBR. Le modèle le plus courant est le modèle de rugosité métallique, utilisé par défaut dans GLTF. Vous pouvez également utiliser le modèle spéculaire-glosiness, mais uniquement avec une extension distincte (extension). Les principaux attributs du matériau sont les suivants:
- nom est le nom du maillage.
- baseColorFactor / baseColorTexture - stocke les informations de couleur. Dans le cas de l'attribut Factor, les informations sont stockées dans une valeur numérique pour RGBA, dans le cas de Texture, le lien vers la texture est stocké dans l'objet textures.
- metallicFactor - stocke les informations métalliques
- roughnessFactor - stocke des informations sur la rugosité
- doubleSided - true ou false (la valeur par défaut) et indique si le maillage sera rendu des deux côtés ou uniquement du côté "avant".
"materials": [ { "pbrMetallicRoughness": { "baseColorTexture": { "index": 0 }, "metallicFactor": 0.0, "roughnessFactor": 0.800000011920929 }, "name": "Nightshade_MAT", "doubleSided": true } ],
Métallique ou le sens de «métallicité». Ce paramètre décrit à quel point il est fortement réfléchissant, comme le vrai métal, c'est-à-dire la quantité de lumière réfléchie par la surface. La valeur est mesurée de 0 à 1, où 0 est un diélectrique et 1 est un métal pur.
Rugosité ou «rugosité». Cet attribut indique le degré de «rugosité» de la surface, affectant ainsi la diffusion de la lumière de la surface. Mesurée de 0 à 1, où 0 est parfaitement plat et 1 est une surface complètement rugueuse qui ne réfléchit qu'une petite quantité de lumière.
Texture - un objet qui stocke des textures (textures). Ces cartes donnent un modèle réaliste. Grâce à eux, vous pouvez désigner l'apparence du modèle, pour donner diverses propriétés telles que la métallicité, la rugosité, la gradation naturelle de l'environnement et même les propriétés de la lueur. Les textures sont décrites par trois tableaux de haut niveau: textures, échantillonneurs, images. L'objet Textures utilise des index pour référencer les instances d'échantillonneur et d'image. L’objet le plus important est l’image, car C'est lui qui stocke les informations de localisation de la carte. Dans les textures, il est décrit par le mot source. L'image peut être située quelque part sur le disque dur (par exemple, «uri»: «duckCM.png») ou encodée en GLTF («bufferView»: 14, «mimeType»: «image / jpeg»). Samplers est un objet qui définit les paramètres de filtrage et d'encapsulation correspondant aux types GL.
Dans notre exemple de triangle, il n'y a pas de textures, mais je donnerai JSON d'autres modèles avec lesquels j'ai travaillé. Dans cet exemple, les textures ont été écrites dans le tampon, elles sont donc également lues à partir du tampon à l'aide de BufferView:
"textures": [ { "sampler": 0, "source": 0 } ], "images": [ { "bufferView": 1, "mimeType": "image/jpeg" } ],
Des animations
GLTF prend en charge les animations cibles articulées, dépouillées et morph à l'aide d'images clés. Les informations de ces trames sont stockées dans des tampons et se réfèrent à des animations utilisant des accesseurs. GLTF 2.0 définit uniquement le magasin d'animations, il ne définit donc aucun comportement d'exécution spécifique, tel que l'ordre de lecture, la lecture automatique, les boucles, l'affichage de la chronologie, etc. Toutes les animations sont stockées dans le tableau Animations et elles sont définies comme un ensemble canaux (attribut de canal), ainsi qu'un ensemble d'échantillons qui sont déterminés par des accesseurs qui traitent les informations sur les images clés et la méthode d'interpolation (attribut échantillons)
Les principaux attributs de l'objet Animations sont les suivants:
- nom - nom de l'animation (le cas échéant)
- canal - un tableau qui connecte les valeurs de sortie des images clés de l'animation à un nœud spécifique de la hiérarchie.
- sampler est un attribut qui fait référence à Accessor, qui traite les images clés du tampon.
- la cible est un objet qui détermine quel nœud (objet Node) doit être animé à l'aide de l'attribut de nœud, et également quelle propriété du nœud doit être animée à l'aide de l'attribut de chemin - traduction, rotation, échelle, poids, etc. Les attributs non animés conservent leurs valeurs lors des animations. Si le nœud n'est pas défini, l'attribut channel doit être omis.
- échantillonneurs - définit les paires d'entrée et de sortie: un ensemble de valeurs scalaires à virgule flottante représentant le temps linéaire en secondes. Toutes les valeurs (entrée / sortie) sont stockées dans le tampon et sont accessibles via des accesseurs. L'attribut d'interpolation stocke la valeur d'interpolation entre les clés.
Il n'y a pas d'animations dans le GLTF le plus simple. Un exemple est tiré d'un autre fichier:
"animations": [ { "name": "Animate all properties of one node with different samplers", "channels": [ { "sampler": 0, "target": { "node": 1, "path": "rotation" } }, { "sampler": 1, "target": { "node": 1, "path": "scale" } }, { "sampler": 2, "target": { "node": 1, "path": "translation" } } ], "samplers": [ { "input": 4, "interpolation": "LINEAR", "output": 5 }, { "input": 4, "interpolation": "LINEAR", "output": 6 }, { "input": 4, "interpolation": "LINEAR", "output": 7 } ] },
La peau
Les informations de skinning, également connues sous le nom de skinning, aka animation osseuse, sont stockées dans le tableau des skins. Chaque habillage est défini à l'aide de l'attribut inverseBindMatrices, qui fait référence à l'accesseur avec des données IBM (matrice de liaison inverse). Ces données sont utilisées pour transférer les coordonnées dans le même espace que chaque articulation, ainsi que l'attribut du tableau des articulations, qui répertorie les indices des nœuds utilisés comme articulations pour l'animation d'habillage. L'ordre des connexions est déterminé dans le tableau skin.joints et doit correspondre à l'ordre des données de inverseBindMatrices. L'attribut squelette pointe vers un objet Node qui est la racine commune de la hiérarchie des articulations, ou le nœud parent direct ou indirect d'une racine commune.
Un exemple d'utilisation de l'objet skin (pas dans l'exemple du triangle):
"skins": [ { "name": "skin_0", "inverseBindMatrices": 0, "joints": [ 1, 2 ], "skeleton": 1 } ]
Les principaux attributs:
- name - skinning name
- inverseBindMatrices - indique le numéro d' accès qui stocke des informations sur la matrice de liaison inverse
- joints - indique le numéro de l'accesseur stockant des informations sur les joints
- squelette - indique le numéro de l'accesseur qui a stocké des informations sur la "racine"
articulation / articulation avec laquelle le squelette du modèle commence
Appareil photo
La caméra détermine la matrice de projection, qui est obtenue en transformant la «vue» en coordonnées du clip. Si c'est plus simple, les caméras déterminent l'aspect visuel (angle de vue, direction du «look», etc.) que l'utilisateur voit lors du chargement du modèle.
La projection peut être «Perspective» et «Orthogonale». Les caméras sont contenues dans des nœuds et peuvent avoir des transformations. Les caméras sont fixées dans des objets Node et peuvent donc avoir des transformations. La caméra est définie de manière à ce que l'axe local + X soit dirigé vers la droite, l'objectif regarde dans la direction de l'axe local -Z et le haut de la caméra est aligné avec l'axe local + Y. Si la transformation n'est pas spécifiée, la caméra est à l'origine. Les caméras sont stockées dans le réseau de caméras. Chacun d'eux définit un attribut de type qui attribue un type de projection (perspective ou orthogonale), ainsi que des attributs tels que perspective ou orthographique, qui stockent déjà des informations plus détaillées. Selon la présence de l'attribut zfar, les caméras avec le type de perspective peuvent utiliser une projection finie ou infinie.
Un exemple de caméra en JSON avec une perspective de type. Non pertinent pour un exemple de fichier GLTF minimal correct (triangle):
"cameras": [ { "name": "Infinite perspective camera", "type": "perspective", "perspective": { "aspectRatio": 1.5, "yfov": 0.660593, "znear": 0.01 } } ]
Les principaux attributs de l'objet Camera:
- name - skinning name
- type - type de caméra, perspective ou orthographique.
- perspective / orthographique - attribut contenant les détails de la valeur de type correspondante
- aspectRatio - Rapport hauteur / largeur (fov).
- yfov - angle de champ de vision vertical (fov) en radians
- zfar - distance par rapport au plan de délimitation éloigné
- znear - distance par rapport au plan de détourage proche
- extras - données spécifiques à l'application
Fichier GLTF valide minimum
Au début de l'article, j'ai écrit que nous collecterons un fichier GLTF minimal qui contiendra 1 triangle. Le JSON tamponné peut être trouvé ci-dessous. Copiez-le simplement dans un fichier texte, changez le format de fichier en .gtlf. Pour afficher un élément 3D dans un fichier, vous pouvez utiliser n'importe quel visualiseur prenant en charge GLTF, mais j'utilise personnellement ce
{ "scenes" : [ { "nodes" : [ 0 ] } ], "nodes" : [ { "mesh" : 0 } ], "meshes" : [ { "primitives" : [ { "attributes" : { "POSITION" : 1 }, "indices" : 0 } ] } ], "buffers" : [ { "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=", "byteLength" : 44 } ], "bufferViews" : [ { "buffer" : 0, "byteOffset" : 0, "byteLength" : 6, "target" : 34963 }, { "buffer" : 0, "byteOffset" : 8, "byteLength" : 36, "target" : 34962 } ], "accessors" : [ { "bufferView" : 0, "byteOffset" : 0, "componentType" : 5123, "count" : 3, "type" : "SCALAR", "max" : [ 2 ], "min" : [ 0 ] }, { "bufferView" : 1, "byteOffset" : 0, "componentType" : 5126, "count" : 3, "type" : "VEC3", "max" : [ 1.0, 1.0, 0.0 ], "min" : [ 0.0, 0.0, 0.0 ] } ], "asset" : { "version" : "2.0" } }
Quel est le résultat?
En conclusion, je tiens à noter la popularité croissante des formats GLTF et GLB, de nombreuses entreprises l'utilisent déjà activement et certaines s'efforcent déjà activement de le faire. La facilité de son utilisation sur le réseau social Facebook (publications 3D et, plus récemment, 3D Photos), l'utilisation active de GLB dans Oculus Home, ainsi qu'un certain nombre d'innovations annoncées lors du GDC 2019 contribuent grandement à la popularisation du format. Légèreté, vitesse de rendu rapide, la facilité d'utilisation, la promotion du groupe Khronos et la standardisation du format sont les principaux avantages qui, j'en suis sûr, finiront par faire leur travail pour le promouvoir davantage!