Badr Abardazzou

Papers · Explainer

A 3D model inside Power BI: four routes, one join

Every route works the same way underneath: the model and the report share one key, the tag. Five minutes.

A plant model shows where things are. A Power BI report shows how they are doing. Click a pump on the model and the report filters to that pump; colour every object by its status and the model becomes the report. Try it on the toy plant below, then see how it is built.

T-101 P-101 P-102 E-301 T-102 V-201
CompleteOpen punchHeld: materialNot started

All tags Click an object, click again to clear.

TagItemState
T-101Hydrotest record signedClosed
T-102Ladder guard missingOpen
T-102Nameplate photoOpen
P-101Alignment checkClosed
P-102Mechanical seal not deliveredHeld
E-301Insulation damaged on nozzleOpen
V-201Loop check not startedOpen
The finished behaviour. A generic plant with invented tags. The colour comes from one measure, the table filters on the clicked tag. Every route below aims at this.

01The pipeline

Whatever the 3D tool, the same five steps carry the model into a report. The one that decides success is step 3.

02The one idea: the tag is the join

A 3D file knows objects by an internal ID. Your trackers know equipment by tag. Power BI needs a table that maps one to the other, then every status table joins on the tag.

Elements (from 3D) ElementIDTag Tags Tag (key) StatusTag, Stage, Date PunchTag, Item, Open? HoldsTag, Reason many : 11 : many Elements (from 3D) ElementIDTag TagsTag (key) StatusTag, Stage PunchTag, Item HoldsTag, Reason
Star around the tag. The visual binds Elements[ElementID] and a colour measure. Filters flow from any status table to the model, and a click on an object flows back.

Three rules make the join hold:

  • Keep the name at export. In glTF 2.0 (GLB is its binary form) every node carries a name and an optional extras object. Write the tag there. In IFC, each object has a GlobalId; keep a table from it to the tag.
  • Extract the table with a script, never by hand. Walk the exported nodes, write ElementID, Tag to a CSV, load it as the Elements table. Re-run it on every new export.
  • Count the orphans. Objects with no tag (pipe supports, steel) stay grey. Tags with no object are equipment missing from the model. Both lists belong on a QA page.

The colour is one DAX measure the visual reads per object:

Status Colour =
VAR held  = CALCULATE ( COUNTROWS ( Holds ) ) > 0
VAR punch = CALCULATE ( COUNTROWS ( Punch ), Punch[Open?] = TRUE () ) > 0
VAR done  = SELECTEDVALUE ( Status[Stage] ) = "Complete"
RETURN
    SWITCH ( TRUE (),
        held,  "#8B1E1E",
        punch, "#C08A2E",
        done,  "#2E6E4E",
        "#B9B6AE" )

03Under the hood: how a click finds its row

A GLB does not keep one mesh per pump. To draw fast, the export merges thousands of objects into a few large meshes, one per discipline and colour for example. So the object's identity travels at the smallest level there is: every vertex carries a number, the row of the tag table it belongs to. Call that number the ElementID.

1 · In the GLB
4444444 7777 one mesh, two objects
vertex  POSITION (x, y, z)   _TAG
 #0     (-2.0, 1.5, 0.0)      4
 #1     ( 1.0, 1.5, 0.0)      4
 ...
 #12    ( 1.6, 2.2, 0.6)      7
2 · In the tag table
ElementIDTagSubsystem
0no tag (steel, supports)
1T-10110-01
2T-10210-02
3E-30130-01
4P-10220-02
5P-10120-01
6V-20120-02
72"-FW-000720-02

The row number is the key. The table adds the tag, and from the tag every status table joins (section 02).

3 · In the report
  1. The user clicks the pump. The viewer finds the triangle under the cursor.
  2. It reads that triangle's _TAG: 4.
  3. Row 4 of the table is P-102. The visual sends the filter Tag = P-102: the punch and hold tables shrink to that pump.
  4. For colour, the visual reads one colour per row from the measure: colour[4] is red (held), so every vertex tagged 4 is painted red.
Three places, one number. The GLB stores a row number on each vertex, the table turns the number into a tag, the report filters and colours by tag. Invented plant, invented tags.

The same table also says where each object sits: a box, given by its lowest and highest corner (X, Y, Z min and max) in metres. Those numbers are small on purpose. GLB stores positions as 32-bit floats, which keep about seven significant digits: at 500,000 m from zero the step between two storable values is about 3 cm, enough to make edges shimmer. So the export subtracts one point, the station origin, and measures heights from grade. Add them back to get plant coordinates.

PLAN (from above) min -2.0, 1.5 max 1.0, 3.0 originE 500.00N 300.00 grid: 3 m squares ELEVATION (from the side) grade = EL 100.00z = 0 z max 1.8EL 101.80 z min 0.0
E = 500.00 + xN = 300.00 + yEL = 100.00 + z
One box per row. P-102 in the table: X -2.0 to 1.0, Y 1.5 to 3.0, Z 0.0 to 1.8. In plant coordinates: E 498.00 to 501.00, N 301.50 to 303.00, EL 100.00 to 101.80. The origin and grade are written once in the file.

How many triangles that GLB should keep, and how to shrink it from megabytes to kilobytes without losing a tag, is measured step by step in How heavy should a 3D model be?

04Four routes, what each can and cannot do

Route 1

A 3D viewer visual from AppSource

CanLives on the report page. Binds the element ID from your model and, where the visual offers it, a colour field, so slicers and filters reach it.

CannotA certified visual cannot call outside services, so the model file has to come from the data or the visual stays uncertified. Cross-filtering back to the report depends on each visual: test it.

Route 2

A 2D view drawn from data (Deneb, HTML Content)

CanDeneb is certified and cross-filters with the report. Draw an isometric picture of the plant, one shape per tag, coloured by a measure.

CannotNo orbit, no zoom into the model. Deneb draws Vega and Vega-Lite, which are 2D grammars.

Route 3

The 3D vendor's own visual

CanAutodesk ships a Viewer visual on AppSource and an open-source APS visual (MIT). Elements filter, highlight and colour from report data.

CannotNeeds the vendor platform: the model hosted there and a token service for the APS visual. You bind to their element IDs.

Route 4

Power BI inside your 3D web app

CanFull 3D (three.js or any viewer). The JavaScript SDK raises dataSelected on a click in the report and accepts setFilters from the viewer.

CannotYou build and host the app, and production embedding needs a capacity (A, EM, P or F SKU).

Two platform limits apply to every visual in routes 1 to 3. A visual reaches the web only if it declares a WebAccess privilege and your admin allows it. A visual receives data in windows of up to 30,000 rows and can fetch more, up to 1,048,576 rows or 100 MB: enough for a tag table, tight for a full model's element list.

05Which route for which need

You needTakeBecause
See status on the plant, inside a normal report, exportable to PowerPointRoute 2Certified visuals keep PowerPoint export and email subscriptions.
Rotate a real model next to the KPIs, models already in Autodesk Docs or ACCRoute 3The model, the IDs and the token already live there.
Rotate a GLB you own, no vendor platformRoute 1Test the visual's file size limit and its click-to-filter first.
A twin with full 3D, many users, your own interfaceRoute 4The viewer drives the report through the SDK.
Just show the model to people who open the dashboardWeb content tileDashboard only, an iframe, no filter link with the report.