← Back to Kiewit — 3D Worlds for VR Rigging-Safety Training

Technical Deep Dive

Kiewit — 3D Worlds for VR Rigging-Safety Training

The Industrial Kit is a Blender 4.2+ add-on plus two small pipelines around it: one that analyzes reference media, and one that bakes and exports the result for Unity.

Reference media → component spec

  1. Frame extraction. ffmpeg samples frames from the site video.
  2. Vision analysis. The site photos, close-ups and sampled frames go to an OpenAI vision model. It returns a structured manifest: one entry per component type, with estimated dimensions in millimetres, hex colours, material, finish, weathering, typical spacing, and which images it appears in.
  3. Defaults. That manifest seeds defaults.py, the kit's single source of truth for metric dimensions (1 Blender unit = 1 m). It doubles as a coverage checklist: every component the model saw should have a generator.

Generator defaults follow real industrial sizes: wide-flange steel sections, ASME B36.10 pipe schedules, and OSHA/EN dimensions for handrails, ladders and stairs.

Generators

Each generator is a pure build_* function written with bmesh, so it works from the add-on's UI or from a script:

FamilyGenerators
Structuralfooting (base plate + anchor bolts), wide-flange column, I-beam, cross-brace, knee-brace, connection plate
Pipingbare pipe, insulated/clad pipe (banding), elbow, flange (bolt circle), reducer, expansion loop, pipe shoe, valve, small-bore line
Accessladder-type cable tray, grating panel (+ toe plate), handrail, caged ladder, stair
Equipmentfloodlight, emissive beacon, equipment skid, concrete slab, concrete wall, worker scale figure
Assemblymulti-bay, multi-tier pipe-rack meta-generator

In the UI, each part appears at the 3D cursor and every parameter is a live slider in Blender's redo panel. Because each generator is a plain function, an agent can also drive it through the Blender MCP server, for example build_rack(bays=5, tiers=3, bay_spacing=6). Kit objects are tagged and kept in their own collection, so the kit never touches the rest of a scene.

All export geometry is real mesh, with no live Geometry Nodes, so FBX output is clean and deterministic.

Materials and the bake

The materials start from scanned PBR textures (via Poly Haven), tinted to the reference colours and weathered. Unity can't read Blender shader nodes, so bake.py bakes each object's material into a standard PBR set:

  • albedo (sRGB)
  • metallic and roughness
  • a tangent-space normal map (OpenGL +Y)
  • ambient occlusion
  • emission

The hero scene is merged into seven meshes (rack, pipes, cable trays, walkway, workers, floor and lights), about 12.5k triangles in total. A decimation pass writes LOD meshes for dense, repeated parts like grating and cable tray.

Getting it into Unity without the usual pain

Blender is Z-up and Unity is Y-up. Two artefacts are classic when moving between them: models arrive rotated −90°, or scaled ×100. The exporter avoids both with −Z forward, +Y up and Apply Transform, at 1 unit = 1 m, so the import Scale Factor is 1. There are two hand-off paths:

  • glTF (.glb): one file carrying geometry, materials and textures. Drag it in with Unity's glTFast and it's done.
  • FBX + editor script: an AssetPostprocessor that runs on import. It sets the texture types, packs metallic and smoothness, detects URP, HDRP or Built-in, builds a material per mesh and remaps it onto the model.

To check a scene quickly, look at the worker figure (about 1.83 m) under the rack, bays of about 6 m, and about 4.5 m of walkable clearance to the first tier.