Skip to main content

Object Caching System

Threebox automatically caches 3D models to improve performance when loading multiple instances of the same object. The objectsCache is a built-in Map that stores loaded models for reuse.

How Caching Works

When you load a 3D model with clone: true (default), Threebox caches the first instance and returns duplicates for subsequent loads:
Threebox.js:76
this.objectsCache = new Map();
The caching logic is implemented in the loadObj method:
Threebox.js:719-744
tb.loadObj(options, callback) {
  if (options.clone === false) {
    // Load new instance without caching
    return new Promise(
      async (resolve) => {
        loader(options, cb, async (obj) => {
          resolve(obj);
        });
      });
  }
  else {
    // Check cache first
    let cache = this.objectsCache.get(options.obj);
    if (cache) {
      cache.promise
        .then(obj => {
          cb(obj.duplicate(options));
        })
        .catch(err => {
          this.objectsCache.delete(options.obj);
          console.error("Could not load model file: " + options.obj);
        });
    } else {
      // Add to cache
      this.objectsCache.set(options.obj, {
        promise: new Promise(
          async (resolve, reject) => {
            loader(options, cb, async (obj) => {
              if (obj.duplicate) {
                resolve(obj.duplicate());
              } else {
                reject(obj);
              }
            });
          })
      });
    }
  }
}

Clone vs No-Clone Strategy

var options = {
  obj: './models/windmill.gltf',
  type: 'gltf',
  scale: 0.1,
  units: 'meters',
  clone: true // Default - uses cache
}

// Load 100 instances efficiently
for (let i = 0; i < 100; i++) {
  tb.loadObj(options, function (model) {
    let lng = origin[0] + Math.random() * 0.4;
    let lat = origin[1] + Math.random() * 0.4;
    model.setCoords([lng, lat, 20]);
    tb.add(model);
  });
}
When clone: true, all instances share the same geometry and textures, significantly reducing GPU memory usage and draw calls.

Performance Monitoring

Threebox provides methods to monitor WebGL resource usage:

Memory Information

// Get memory statistics
let memory = tb.memory();
console.log('Geometries:', memory.geometries);
console.log('Textures:', memory.textures);

// Get program count
let programCount = tb.programs();
console.log('WebGL Programs:', programCount);

Real-Time Performance Stats

Combine with Three.js Stats module for comprehensive monitoring:
import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';

let stats = new Stats();
map.getContainer().appendChild(stats.dom);

function animate() {
  requestAnimationFrame(animate);
  stats.update();
}
animate();

Optimization Best Practices

Use Object Caching

Enable clone: true for repeated models to share geometry and textures

Limit Draw Calls

Cloned objects result in fewer GPU draw calls - 1 vs N for non-cloned

Dispose Properly

Use tb.dispose() to free resources before navigation

Monitor Memory

Regularly check tb.memory() to track resource usage

Calculating GPU Memory Usage

From the performance example, here’s how to estimate memory:
Threebox.js:250-263
function getGeometryByteLength(geometry) {
  var total = 0;
  
  if (geometry.index) {
    total += geometry.index.array.byteLength;
  }
  
  for (var name in geometry.attributes) {
    total += geometry.attributes[name].array.byteLength;
  }
  
  return total;
}
Without proper caching, 100 objects could consume 100x the memory and create 100 draw calls instead of 1.

Performance Comparison

MethodGPU Draw CallsGPU MemoryWebGL GeometriesWebGL Textures
Cloned (100 objects)1~5 MB1x1x
Non-Cloned (100 objects)100~500 MB100x100x

Clear and Dispose

Clearing Objects

Threebox.js:947-971
// Clear all objects
await tb.clear();

// Clear objects from specific layer
await tb.clear('custom_layer');

// Clear and dispose resources
await tb.clear(null, true);

Complete Disposal

Threebox.js:1092-1114
// Dispose all resources before navigation
await tb.dispose();
The dispose() method:
  • Clears all objects from tb.world
  • Disposes cached objects in objectsCache
  • Removes the map instance
  • Frees WebGL resources
  • Cleans up the renderer
Always call tb.dispose() before navigating away from a page using Threebox to prevent memory leaks.

Build docs developers (and LLMs) love