PhotoTo3D DOCS
Engineering

Performance and optimization

Why primitive assemblies are light, and the honest tradeoffs when they are not.

Why assemblies stay light

A generated model is a handful of parametric primitives — boxes, spheres, cylinders, capsules, cones and torus rings. Their geometry is generated on the CPU at construction time with modest segment counts, so total vertex counts stay small compared to a scanned or sculpted mesh.

There is no runtime download of a GLB or texture atlas, and no decode step. The cost is a bit of JavaScript at construction and then ordinary Three.js rendering.

Draw calls are the real budget

Each part is a separate THREE.Mesh, so a model with forty nodes issues roughly forty draw calls. On its own that is cheap, but a scene full of instances multiplies quickly, and draw calls — not vertices — are usually what caps frame rate on a primitive assembly.

If a model does not need per-part animation, merge its static geometry into one buffer so the whole thing draws in a single call. Parts that must move should stay separate so you can still address them through the runtime.

import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
// Merge only the parts that never animate; keep movable nodes separate.

Instance repeated models

When the same model appears many times — crates, props, enemies — do not add many Groups. Draw the shared geometry with THREE.InstancedMesh and a per-instance matrix so the GPU renders every copy in one call.

This trades away per-part runtime access for that shared geometry, so reserve instancing for background or crowd objects and keep hero pieces as full factory Groups you can animate.

When to simplify

The method is a poor fit for dense organic surfaces; forcing detail there inflates node counts without matching the reference. If a model is heavier than it should be, lower radialSegments in the spec before adding parts, and drop nodes that do not carry a critical feature.

Be honest about the target. A hero object earns more parts and higher segment counts; a distant prop should be the fewest primitives that still read correctly at its on-screen size.