from bim to unity: real-time importer
date: July 22, 2020
Problem: BIM models change constantly during construction. Pre-baked Unity builds are outdated before deployment. The standard approach (export from Revit, import to Unity, build, deploy) requires a full rebuild cycle for every model update.
Solution: Dynamic loading. Connect directly to the BIM database, stream geometry and metadata at runtime, display current state without rebuilds. A type library pattern keeps memory efficient by loading unique element types once and instantiating many times.
Architecture
Types define what something is (geometry, materials). Elements define where instances exist (position, rotation, parameters). Keeping these concerns separate makes the pipeline predictable and memory efficient.
Type library pattern
A building might have 500 doors but only 15 door types. Load each type once, instantiate many times.
The import runs in two passes. First, process all type definitions and build the type library. Second, process element instances referencing types by ID. Geometry data lives in the type library. Elements store only transform and parameter data.
Without the type library, memory scales linearly with element count. With it, memory scales with unique type count, typically 5-10% of total elements. A building with 50,000 elements but 3,000 unique types stores geometry for 3,000 objects, not 50,000.
Coordinate system transformation
BIM uses right-handed coordinates. Unity uses left-handed. The naive fix transforms every vertex during import. Instead, a handedness corrector flips the entire hierarchy in one operation.
private static ModelController CreateModel(
Dictionary<long, BimObject> data,
Transform parent)
{
Transform handednessCorrector = new GameObject("Handedness Corrector").transform;
handednessCorrector.transform.SetParent(parent);
handednessCorrector.transform.localPosition = Vector3.zero;
handednessCorrector.transform.localRotation = Quaternion.identity;
handednessCorrector.transform.localScale = Vector3.one;
// ... build hierarchy under handednessCorrector ...
if (!ApplicationConfiguration.Configuration.Model.UseRhs)
{
handednessCorrector.localScale = new Vector3(-1, 1, 1);
}
ModelController mc = parent.gameObject.AddComponent<ModelController>();
mc.Categories = handednessCorrector.gameObject
.AddComponent<CategoryController>();
return mc;
}
One operation instead of transforming each vertex. All child transforms flip correctly. Rotations remain valid.
The origin problem
BIM models use real-world coordinates. A building in Amsterdam might sit at (121000, 485000) meters in the Dutch RD system. Unity uses 32-bit floats for position values. At those distances, precision errors reach centimeters. Objects jitter. Vertices dance.
The solution: offset all coordinates relative to a reference point within the model.
Vector3 bimPosition = element.transform.ExtractPosition(); // (121543, 12, 485221)
Vector3 modelOrigin = modelReferencePoint; // (121500, 0, 485200)
Vector3 unityPosition = (bimPosition - modelOrigin) * scale; // (43, 12, 21) * 0.001
The AR anchoring system handles real-world positioning separately through QR markers. Internal geometry stays origin-relative. Result: Sub-millimeter precision regardless of where the building sits on Earth.
Hierarchical organization
The importer maintains BIM's natural hierarchy: Category, Storey, Element. This structure enables filtering without custom logic. Categories let users hide all doors and show only structure. Storeys let them isolate a specific floor. To hide all doors, deactivate the Doors GameObject. Simple, fast, predictable.
JSON proxy pattern
BIM data is verbose. A single element can have dozens of properties. Lightweight proxy classes extract only what rendering needs: ID, vertices, submeshes, category, name. If detailed data is needed later, request it specifically for selected elements rather than loading everything upfront.
On typical hardware, the importer processes around 2,000 elements per second. A 50,000-element building uses about 200MB of memory. Hierarchy construction completes in under 500ms.
Most AR-BIM solutions require pre-baked models. This approach loads directly from live BIM databases. The model in AR is always the model in the database, so there's never a question of whether you're looking at stale data.