Skip to content

glTF Models

Narta Xaymar Dirks edited this page Nov 1, 2026 · 1 revision

glTF models

LoadMesh and LoadAnimMesh read glTF 2.0 files with the cgltf library (an extension: the original has no glTF): .gltf files, which are JSON with the data in files next to them or inside as data: uris, and .glb files, which hold the JSON and the data in one file. The file type is told by what is in the file, not by its name. LoadMesh makes one mesh of the model as it looks without animation, LoadAnimMesh keeps every node as an entity with the animation of the file and works with Animate, SetAnimTime, FindChild and LoadAnimSeq.

  • glTF is right-handed with y up, Blitz3D is left-handed with y up, and both have the front of a model at +z. The conversion mirrors x: positions, normals and translations change the sign of x, rotations are mirrored with them, and two corners of every triangle change places (the front of a Blitz3D face is where its corners go around the other way). A model that faces +z in glTF faces +z here, and its left hand stays on its left. The vertices of a surface come in the order that the faces use them. The pictures of glTF start at the top, as those of Blitz3D do, so the texture coordinates are not changed. The unit is what the file says (glTF says meters).
  • Every node is an entity with the name of the node, its translation, rotation and scale (or its matrix, without a skew), below one entity at the top that stands for the scene. A node that has a mesh is a mesh entity. The scene of the file is loaded, or the first one, or everything if the file has none. Lights (KHR_lights_punctual: directional, point and spot) and cameras of the file are entities too: each is a child of the entity of its node, named like the light or camera (or <node> light / <node> camera) and turned half a turn, so that it looks along the file's -Z in the same way as in other glTF viewers. A light keeps its color, range and the cone angles of a spot light (the intensity is not used). A camera is made with CameraProjMode 0, so that it does not draw over the camera of the program until you switch it on with CameraProjMode; its zoom comes from the field of view and its range from znear and zfar.
  • A mesh with more than one primitive has a surface for each material. Triangles, triangle strips and fans are read; points and lines are not. Indices of 8, 16 and 32 bits, and positions, normals, two sets of coordinates (TEXCOORD_0 and TEXCOORD_1), vertex colors (COLOR_0, with or without alpha, set on the vertices, EntityFX 2 shows them) and the quantized integer forms of these (KHR_mesh_quantization) are read. A primitive without normals gets smooth ones made. Tangents and morph targets are not used.
  • A material becomes a brush: baseColorFactor is the color and alpha, baseColorTexture the picture, 1 - roughnessFactor the shininess, doubleSided is EntityFX 16 and KHR_materials_unlit is EntityFX 1. The alpha mode OPAQUE ignores the alpha of the color, BLEND gives the picture an alpha channel (flag 2) and MASK cuts it out (flag 4, at an alpha of one half whatever alphaCutoff says). KHR_texture_transform (offset, rotation and scale, and texCoord) is put into the texture coordinates of the vertices, and the sampler's CLAMP_TO_EDGE wrapping becomes the clamp flags 16 and 32 (mirrored wrapping is a repeat). The picture is found next to the model, as for every model; .png and .jpg are what glTF uses, the formats of Image formats work as well, and EXT_texture_webp, EXT_texture_avif and KHR_texture_basisu are tried when a texture has no source.
  • Blitz3D has one picture for a brush: the metallic-roughness, normal, occlusion and emissive textures are not used, and neither are the emissive color and KHR_materials_emissive_strength. Roughness and metalness are only the shininess. A normal map would need the tangent space, which the lighting of Blitz3D (Dot3) does not have, so it is left out on purpose.
  • A node with a skin is skinned: each vertex has up to eight joints (JOINTS_0 and JOINTS_1) with their weights (WEIGHTS_0 and WEIGHTS_1), which are made to add up to 1, and the joints are entities that Animate moves. The node's own place is left out for a skinned mesh, as glTF says. The inverse bind matrices of the file say how the vertices go into the space of each joint; a joint that several skins use has the matrix of the first one that names it.
  • The animations move the translation, rotation and scale of nodes (not weights). Time is in seconds, one second is 60 frames. The first animation starts at frame 0; with more than one in a file, each starts one frame after the one before it and AnimLength is the end of the last. They are one animation with several sequences: sequence 0 is everything and sequence 1, 2 and so on are the animations of the file in their order. A node that an animation does not touch is at its starting pose while the animation plays. LINEAR is interpolated (rotations on the shortest way), STEP holds until the next key, and CUBICSPLINE is evaluated at eight places between keys.
  • The pictures inside a glTF file can be loaded with LoadTexture and LoadImage: LoadTexture("model.glb") gives the first picture of the file, LoadTexture("model.glb#2") the third (the numbers are those of images in the file). The picture can be a data: uri, a view of a buffer or a file next to the model, and 0 is the result if there is no such picture. LoadAnimImage and the other commands that load a picture file read them the same way.

Home · Command Index



Differences
Language Features
BlitzBasic
Blitz3D
BlitzPlus

Clone this wiki locally