15.6. glTF 2.0 loader (dasGLTF): GLB/.gltf parse, accessor decode, node hierarchy, skinning and keyframe animation into a backend-neutral scene

dasGLTF loads glTF 2.0 models — .glb (binary), .gltf (JSON), external or base64-embedded buffers — into a backend-neutral scene, with no new native code (it builds on json_boost, base64, fio, stbimage and math).

The backend-neutral core parses, decodes accessors, builds the node hierarchy, and evaluates skinning and keyframe animation with no OpenGL or Vulkan dependency — usable headless for tooling or a future renderer. Require it with:

require gltf/gltf_boost

An opt-in OpenGL adapter (gltf/gltf_gl + gltf/gltf_pbr, requiring dasOpenGL / dasGlsl) maps a loaded scene to GL buffers and renders it with a Cook-Torrance metallic-roughness PBR shader; it is documented with the OpenGL examples, not here.

15.6.1. The scene model

load_gltf returns a GltfScene, which aggregates the meshes, materials, textures, images, samplers, nodes, skins and animations of the default scene. Geometry is decoded to a fixed GltfVertex layout (position, normal, tangent, two UV sets, color, and joints/weights decoded to float4), so interleaved, normalized and integer-lane attributes need no downstream handling.

require gltf/gltf_boost

var scene <- load_gltf("model.glb")
update_world_transforms(scene)              // fill GltfNode.world from the hierarchy
let (mn, mx) = gltf_scene_bounds(scene)     // world-space AABB for auto-framing

15.6.2. Animation and skinning

evaluate_animation samples one animation at a time t (STEP / LINEAR / CUBICSPLINE), writes the result into each target node’s TRS, and refreshes the world transforms. gltf_joint_matrix returns the per-joint skinning matrix (jointNode.world * inverseBind[j]) that deforms skinned geometry. Morph targets and saving/export are out of scope.

15.6.2.1. Enumerations

GltfAlphaMode

enum GltfAlphaMode

GltfInterp

enum GltfInterp

GltfPath

enum GltfPath

GltfPrimitiveMode

enum GltfPrimitiveMode

15.6.2.2. Structures

GltfVertex

struct GltfVertex

GltfPrimitive

struct GltfPrimitive

GltfMesh

struct GltfMesh

GltfMaterial

struct GltfMaterial

GltfImage

struct GltfImage

GltfSampler

struct GltfSampler

GltfTexture

struct GltfTexture

GltfNode

struct GltfNode

GltfSkin

struct GltfSkin

GltfAnimSampler

struct GltfAnimSampler

GltfAnimChannel

struct GltfAnimChannel

GltfAnimation

struct GltfAnimation

GltfScene

struct GltfScene

15.6.2.3. Loading

load_gltf(path: string ): GltfScene

Load a glTF 2.0 file (.gltf, .glb, or base64-embedded .gltf) into a backend-agnostic GltfScene. Returns an empty scene on failure.

Arguments:
  • path : string

load_gltf_from_memory(bytes: array<uint8>; baseDir: string = "" ): GltfScene

Load a glTF 2.0 document (.gltf JSON, .glb binary, or base64-embedded .gltf) from an in-memory byte buffer. baseDir resolves external buffer/image URIs (pass “” for a self-contained .glb). Returns an empty scene on failure.

Arguments:
  • bytes : array<uint8>

  • baseDir : string

15.6.2.4. Scene, skinning and animation

evaluate_animation(scene: GltfScene; animation: int; t: float )

Evaluate animation animation at time t (seconds): sample each channel and write the result into its target node’s TRS, then recompose those nodes’ local matrices and refresh every world transform. Nodes given by an explicit matrix are never animation targets (glTF forbids it), so only touched (hence TRS-defined) nodes are recomposed — matrix-defined nodes keep their parsed local.

Arguments:
  • scene : GltfScene

  • animation : int

  • t : float

gltf_joint_matrix(scene: GltfScene; skinIndex: int; j: int ): float4x4

Skinning matrix for joint slot j of skin skinIndex: jointNode.world * inverseBind[j]. This is the palette the GPU multiplies each skinned vertex by; the mesh node’s own transform is intentionally omitted (glTF renders skinned geometry directly in skin space). Returns identity for an invalid index.

Arguments:
gltf_scene_bounds(scene: GltfScene ): tuple<float3;float3>

World-space axis-aligned bounds (min, max) over every mesh vertex, using each node’s world transform. Returns (0, 0) for a scene with no drawable vertices. Handy for auto-framing a camera.

Arguments:
update_world_transforms(scene: GltfScene )

Recompute every node’s world transform by walking the hierarchy from the scene roots (world = parent.world * local).

Arguments:

15.6.2.5. Accessor byte readers

gltf_comp_size(compType: int ): int64

Byte size of one accessor component for the given glTF componentType.

Arguments:
  • compType : int

gltf_rd_f32(b: array<uint8>|array<uint8>#; o: int64 ): float

def gltf_rd_f32 (b: array<uint8>|array<uint8>#; o: int64) : float

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_rd_i16(b: array<uint8>|array<uint8>#; o: int64 ): int

def gltf_rd_i16 (b: array<uint8>|array<uint8>#; o: int64) : int

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_rd_i8(b: array<uint8>|array<uint8>#; o: int64 ): int

def gltf_rd_i8 (b: array<uint8>|array<uint8>#; o: int64) : int

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_rd_u16(b: array<uint8>|array<uint8>#; o: int64 ): uint

def gltf_rd_u16 (b: array<uint8>|array<uint8>#; o: int64) : uint

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_rd_u32(b: array<uint8>|array<uint8>#; o: int64 ): uint

def gltf_rd_u32 (b: array<uint8>|array<uint8>#; o: int64) : uint

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_rd_u8(b: array<uint8>|array<uint8>#; o: int64 ): uint

def gltf_rd_u8 (b: array<uint8>|array<uint8>#; o: int64) : uint

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

gltf_read_comp_float(b: array<uint8>|array<uint8>#; o: int64; compType: int; normalized: bool ): float

Read one component at byte offset o as float, applying glTF normalized integer→float conversion (unsigned: /max; signed: max(v/max, -1)).

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

  • compType : int

  • normalized : bool

gltf_read_comp_uint(b: array<uint8>|array<uint8>#; o: int64; compType: int ): uint

Read one component at byte offset o as uint (index accessors: u8/u16/u32).

Arguments:
  • b : option<array<uint8>| array<uint8>#>

  • o : int64

  • compType : int

gltf_type_ncomp(t: string ): int

Number of components for a glTF accessor type string (SCALAR/VECn/MATn).

Arguments:
  • t : string