www.xbdev.net
xbdev - software development
Thursday April 16, 2026
Home | Contact | Support | glTF File Format The JPG of 3D Formats ...
     
 

glTF File Format Tutorials

Unlocking the power ...

 


The glTF File Format.
The glTF File Format.


Complete Vanilla JavaScript class for loading and parsing the 3D File format (glTF)


The complete code is given below for the loader/dumper. You can try an online version here (LINK).

The 100 lines of code below is a glTF parser written in vanilla JavaScript for loading, parsing and dumping the data for the 3d model in the file.

class glTFLoader {
    async load(url, gltfPath) {
        try {
            const response = await fetch(url);
            const gltf = await response.json();
            gltf.gltfPath = gltfPath;
            const parsedData = await this.parseGLTF(gltf);
            return parsedData;
        } catch (error) {
            console.error('Error loading GLTF file:', error);
            throw error;
        }
    }

    async parseGLTF(gltf) {
        const parsedData = {
            buffers: await this.loadBuffers(gltf),
            bufferViews: gltf.bufferViews,
            accessors: gltf.accessors,
            meshes: gltf.meshes,
            nodes: gltf.nodes,
            materials: gltf.materials,
            textures: gltf.textures,
            animations: gltf.animations,
        };

        this.extractMeshData(parsedData);
        this.extractAnimations(parsedData);
        this.extractTextures(parsedData);

        return parsedData;
    }

    async loadBuffers(gltf) {
        const bufferPromises = gltf.buffers.map(buffer => fetch( gltf.gltfPath + buffer.uri ).then(res => res.arrayBuffer()));
        return await Promise.all(bufferPromises);
    }

    extractMeshData(parsedData) {
        parsedData.meshes.forEach(mesh => {
            mesh.primitives.forEach(primitive => {
                const positionAccessorIndex = primitive.attributes.POSITION;
                const positionAccessor = parsedData.accessors[positionAccessorIndex];
                const positionBufferView = parsedData.bufferViews[positionAccessor.bufferView];
                const positionBuffer = parsedData.buffers[positionBufferView.buffer];

                const positions = new Float32Array(
                    positionBuffer,
                    positionBufferView.byteOffset + (positionAccessor.byteOffset || 0),
                    positionAccessor.count * (positionAccessor.type === 'VEC3' ? 3 : 1)
                );
                primitive.positions = positions;

                if (primitive.indices !== undefined) {
                    const indexAccessor = parsedData.accessors[primitive.indices];
                    const indexBufferView = parsedData.bufferViews[indexAccessor.bufferView];
                    const indexBuffer = parsedData.buffers[indexBufferView.buffer];

                    const indices = new Uint16Array(
                        indexBuffer,
                        indexBufferView.byteOffset + (indexAccessor.byteOffset || 0),
                        indexAccessor.count
                    );
                    primitive.indices = indices;
                }

                if (primitive.attributes.NORMAL !== undefined) {
                    const normalAccessorIndex = primitive.attributes.NORMAL;
                    const normalAccessor = parsedData.accessors[normalAccessorIndex];
                    const normalBufferView = parsedData.bufferViews[normalAccessor.bufferView];
                    const normalBuffer = parsedData.buffers[normalBufferView.buffer];

                    const normals = new Float32Array(
                        normalBuffer,
                        normalBufferView.byteOffset + (normalAccessor.byteOffset || 0),
                        normalAccessor.count * (normalAccessor.type === 'VEC3' ? 3 : 1)
                    );
                    primitive.normals = normals;
                }

                if (primitive.attributes.TEXCOORD_0 !== undefined) {
                    const texCoordAccessorIndex = primitive.attributes.TEXCOORD_0;
                    const texCoordAccessor = parsedData.accessors[texCoordAccessorIndex];
                    const texCoordBufferView = parsedData.bufferViews[texCoordAccessor.bufferView];
                    const texCoordBuffer = parsedData.buffers[texCoordBufferView.buffer];

                    const texCoords = new Float32Array(
                        texCoordBuffer,
                        texCoordBufferView.byteOffset + (texCoordAccessor.byteOffset || 0),
                        texCoordAccessor.count * (texCoordAccessor.type === 'VEC2' ? 2 : 1)
                    );
                    primitive.texCoords = texCoords;
                }
            });
        });
    }

    extractAnimations(parsedData) {
        if (parsedData.animations) {
            parsedData.animations.forEach(animation => {
                animation.samplers.forEach(sampler => {
                    const inputAccessor = parsedData.accessors[sampler.input];
                    const inputBufferView = parsedData.bufferViews[inputAccessor.bufferView];
                    const inputBuffer = parsedData.buffers[inputBufferView.buffer];

                    sampler.inputData = new Float32Array(
                        inputBuffer,
                        inputBufferView.byteOffset + (inputAccessor.byteOffset || 0),
                        inputAccessor.count
                    );

                    const outputAccessor = parsedData.accessors[sampler.output];
                    const outputBufferView = parsedData.bufferViews[outputAccessor.bufferView];
                    const outputBuffer = parsedData.buffers[outputBufferView.buffer];

                    sampler.outputData = new Float32Array(
                        outputBuffer,
                        outputBufferView.byteOffset + (outputAccessor.byteOffset || 0),
                        outputAccessor.count * (outputAccessor.type === 'VEC3' ? 3 : 1)
                    );
                });
            });
        }
    }

    extractTextures(parsedData) {
        if (parsedData.textures) {
            parsedData.textures.forEach(texture => {
                if (texture.source !== undefined) {
                    const image = parsedData.images[texture.source];
                    texture.imageUri = image.uri;
                }
            });
        }
    }
}

// Function to display statistics
function displayStats(parsedData) {
    
    const stats = {
        numberOfMeshes: parsedData.meshes ? parsedData.meshes.length : 0,
        numberOfNodes: parsedData.nodes ? parsedData.nodes.length : 0,
        numberOfMaterials: parsedData.materials ? parsedData.materials.length : 0,
        numberOfTextures: parsedData.textures ? parsedData.textures.length : 0,
        numberOfAnimations: parsedData.animations ? parsedData.animations.length : 0,
    };

    let details = `
        Number of Meshes: ${stats.numberOfMeshes}<br>
        Number of Nodes: ${stats.numberOfNodes}<br>
        Number of Materials: ${stats.numberOfMaterials}<br>
        Number of Textures: ${stats.numberOfTextures}<br>
        Number of Animations: ${stats.numberOfAnimations}<br>
        <h2>Mesh Details:</h2>
    `;

    parsedData.meshes.forEach((mesh, meshIndex) => {
        details += `Mesh ${meshIndex} - Name: ${mesh.name || 'Unnamed'}<br>`;
        mesh.primitives.forEach((primitive, primitiveIndex) => {
            const verticesCount = primitive.positions ? primitive.positions.length / 3 : 0;
            const indicesCount = primitive.indices ? primitive.indices.length : 0;
            details += `
                ${' '.repeat(8)}Primitive ${primitiveIndex}:<br>
                ${' '.repeat(16)}Number of Vertices: ${verticesCount}<br>
                ${' '.repeat(16)}Number of Indices: ${indicesCount}<br>
            `;
        });
    });
  
    const statsDiv = document.createElement('div');
    document.body.appendChild( statsDiv );
      statsDiv.innerHTML = details;
}

// Function to load GLTF file and display statistics
async function loadGLTFAndShowStats(url, gltfPath) {
    const loader = new glTFLoader();
    try {
        const parsedData = await loader.load(url, gltfPath);
        displayStats(parsedData);
    } catch (error) {
        console.error('An error occurred:', error);
    }
}



const gltfFileUrl = 'https://webgpulab.xbdev.net/var/resources/gltf/lowpolyworld.gltf';
const gltfPath = 'https://webgpulab.xbdev.net/var/resources/gltf/';

let div = document.createElement('div');
document.body.appendChild( div );
div.innerHTML = `
Vanilla glTF loader/parser in native JavaScript<br><br>

File: ${gltfFileUrl}<br><br>
`;


loadGLTFAndShowStats(gltfFileUrl, gltfPath);


console.log('done..');


This is what the output for the loader/dump script above looks like:


<?php
Vanilla glTF loader/parser in native JavaScript

File: https://webgpulab.xbdev.net/var/resources/gltf/lowpolyworld.gltf

Number of Meshes: 40
Number of Nodes: 40
Number of Materials: 22
Number of Textures: 0
Number of Animations: 0
Mesh Details:
Mesh 0 - Name: Плоскость.003_Плоскость.000
        Primitive 0:
                Number of Vertices: 224
                Number of Indices: 408
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 288
        Primitive 2:
                Number of Vertices: 246
                Number of Indices: 456
        Primitive 3:
                Number of Vertices: 1040
                Number of Indices: 1536
        Primitive 4:
                Number of Vertices: 68
                Number of Indices: 108
        Primitive 5:
                Number of Vertices: 300
                Number of Indices: 504
        Primitive 6:
                Number of Vertices: 277
                Number of Indices: 423
        Primitive 7:
                Number of Vertices: 800
                Number of Indices: 1200
        Primitive 8:
                Number of Vertices: 1256
                Number of Indices: 2172
        Primitive 9:
                Number of Vertices: 4552
                Number of Indices: 9108
        Primitive 10:
                Number of Vertices: 32
                Number of Indices: 60
        Primitive 11:
                Number of Vertices: 48
                Number of Indices: 72
Mesh 1 - Name: Plane.013
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 2 - Name: Plane.012
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 3 - Name: Plane.011
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 4 - Name: Plane.010
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 5 - Name: Plane.009
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 6 - Name: Plane.008
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 7 - Name: Plane.007
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 8 - Name: Plane
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 9 - Name: Plane.001
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 10 - Name: Plane.006
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 11 - Name: Plane.002
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 12 - Name: Plane.004
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 13 - Name: Plane.005
        Primitive 0:
                Number of Vertices: 4
                Number of Indices: 6
Mesh 14 - Name: Cylinder.024
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 15 - Name: Cylinder.023
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 16 - Name: Cylinder.022
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 17 - Name: Cylinder.021
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 18 - Name: Cylinder.020
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 19 - Name: Cylinder.019
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 20 - Name: Cylinder.018
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 21 - Name: Cylinder.017
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 22 - Name: Cylinder.016
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 23 - Name: Icosphere.005
        Primitive 0:
                Number of Vertices: 720
                Number of Indices: 720
Mesh 24 - Name: Cylinder.015
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 25 - Name: Cylinder.014
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 26 - Name: Cylinder.013
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 27 - Name: Cylinder.012
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 28 - Name: Cylinder.011
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 29 - Name: Cylinder.010
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 30 - Name: Cylinder.009
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 31 - Name: Icosphere.003
        Primitive 0:
                Number of Vertices: 720
                Number of Indices: 720
Mesh 32 - Name: Cylinder.001
        Primitive 0:
                Number of Vertices: 108
                Number of Indices: 180
        Primitive 1:
                Number of Vertices: 168
                Number of Indices: 168
Mesh 33 - Name: Cylinder.008
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 34 - Name: Cylinder.007
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 35 - Name: Cylinder.006
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 36 - Name: Cylinder.005
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 37 - Name: Cylinder.002
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132
Mesh 38 - Name: Plane.003
        Primitive 0:
                Number of Vertices: 472
                Number of Indices: 1386
        Primitive 1:
                Number of Vertices: 176
                Number of Indices: 288
        Primitive 2:
                Number of Vertices: 156
                Number of Indices: 252
Mesh 39 - Name: Cylinder.004
        Primitive 0:
                Number of Vertices: 36
                Number of Indices: 60
        Primitive 1:
                Number of Vertices: 132
                Number of Indices: 132




Resources & Links


• glTF Loader/Dumper LINK

• glTF Tutorials/Code/Examples LINK





























Ray-Tracing with WebGPU kenwright WebGPU Development Cookbook - coding recipes for all your webgpu needs! WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Games WGSL 2d 3d interactive web-based fun learning WebGPU Compute WebGPU API - Owners WebGPU & WGSL Essentials: A Hands-On Approach to Interactive Graphics, Games, 2D Interfaces, 3D Meshes, Animation, Security and Production Kenwright graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu for dummies kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright WebGPU Shader Language Development: Vertex, Fragment, Compute Shaders for Programmers Kenwright wgsl webgpugems shading language cookbook kenwright WGSL Fundamentals book kenwright WebGPU Data Visualization Cookbook kenwright Special Effects Programming with WebGPU kenwright WebGPU Programming Guide: Interactive Graphics and Compute Programming with WebGPU & WGSL kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2026 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.