Expand description
Renderer-neutral geometry and viewer helpers for IFC5 / IFCX.
The crate decodes the geometry and presentation attributes of
ifcx_alpha nodes into typed values. It never depends on a renderer or
GPU API (see docs/adr/0002).
| Module | Attribute | Result |
|---|---|---|
transform | usd::xformop | Transform, composed with world_from_parent |
mesh | usd::usdgeom::mesh | TriangleMesh |
curves | usd::usdgeom::basiscurves | CurveGeometry |
points | points::array, points::base64, pcd::base64 | PointCloud |
presentation | usd::usdgeom::visibility, bsi::ifc::presentation::*, gltf::material | NodePresentation, resolved over ancestors by is_visible, resolve_basic_material, and resolve_mesh_material |
scene | all of the above, over a composed tree | RenderScene: instances with node path, world matrix, shared f32 buffers, materials, bounds |
glb | a RenderScene | binary glTF 2.0 bytes, to_glb |
Each decoder takes the attribute’s serde_json::Value as stored in
[openbim_ifcx::IfcxNode::attributes] and returns a DecodeError for
malformed values instead of panicking. PointCloud::from_attributes and
NodePresentation::from_attributes pick their attributes from anything
implementing Attributes. Coordinates stay f64; see math.
RenderScene::from_composition walks a composed node tree once and
returns the flat scene a viewer draws, with each shared geometry stored
once and instanced. to_glb writes that scene as a binary glTF 2.0 file;
the ifcx2glb example converts IFCX files from the command line.
use openbim_ifcx::IfcxFile;
use openbim_ifcx_geometry::{mesh, transform, Transform, TriangleMesh};
let file = IfcxFile::from_json_str(r#"{
"header": {"id": "demo", "ifcxVersion": "ifcx_alpha", "dataVersion": "1.0.0",
"author": "someone", "timestamp": "2026-10-03"},
"imports": [], "schemas": {},
"data": [{"path": "slab", "attributes": {
"usd::xformop": {"transform": [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,3,1]]},
"usd::usdgeom::mesh": {"points": [[0,0,0],[1,0,0],[0,1,0]],
"faceVertexIndices": [0,1,2]}
}}]
}"#)?;
let attributes = file.data[0].attributes.as_ref().unwrap();
let local = Transform::from_attribute(&attributes[transform::ATTRIBUTE])?;
let mesh = TriangleMesh::from_attribute(&attributes[mesh::ATTRIBUTE])?;
let world: Vec<_> = mesh.positions.iter().map(|&p| local.transform_point(p)).collect();
assert_eq!(world[1], [1.0, 0.0, 3.0]);Point clouds and presentation:
use openbim_ifcx_geometry::{is_visible, resolve_basic_material, NodePresentation, PointCloud};
use serde_json::json;
let node = json!({
"points::array": {"positions": [[0, 0, 0], [1, 0, 0]]},
"bsi::ifc::presentation::diffuseColor": [1, 0, 0],
});
let attributes = node.as_object().unwrap();
let cloud = PointCloud::from_attributes(attributes)?.unwrap();
assert_eq!(cloud.positions, [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0]]);
let own = NodePresentation::from_attributes(attributes)?;
assert!(is_visible(true, own.visibility));
assert_eq!(resolve_basic_material([&own]).color, [1.0, 0.0, 0.0]);A render scene from a composed file:
use openbim_ifcx::{compose, flatten_owned, IfcxFile};
use openbim_ifcx_geometry::{GeometryKind, RenderScene, SceneOptions};
let file = IfcxFile::from_json_str(r#"{
"header": {"id": "demo", "ifcxVersion": "ifcx_alpha", "dataVersion": "1.0.0",
"author": "someone", "timestamp": "2026-10-03"},
"imports": [], "schemas": {},
"data": [
{"path": "storey", "children": {"Slab": "slab"}, "attributes": {
"usd::xformop": {"transform": [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,3,1]]},
"bsi::ifc::presentation::diffuseColor": [0.8, 0.2, 0.2]}},
{"path": "slab", "attributes": {"usd::usdgeom::mesh": {
"points": [[0,0,0],[1,0,0],[0,1,0]], "faceVertexIndices": [0,1,2]}}}
]
}"#)?;
let composition = compose(&flatten_owned(file.data))?;
let scene = RenderScene::from_composition(&composition, &SceneOptions::default());
let slab = &scene.instances[0];
assert_eq!(slab.path, "storey/Slab");
assert_eq!(slab.geometry.kind(), GeometryKind::Mesh);
assert_eq!(slab.world.translation(), [0.0, 0.0, 3.0]);
assert!(scene.warnings.is_empty());Re-exports§
pub use curves::CurveGeometry;pub use curves::Polyline;pub use curves::UnsupportedCurve;pub use error::DecodeError;pub use glb::to_glb;pub use glb::GlbError;pub use glb::GlbOptions;pub use math::Vec3;pub use mesh::TriangleMesh;pub use points::PointCloud;pub use presentation::is_visible;pub use presentation::resolve_basic_material;pub use presentation::resolve_mesh_material;pub use presentation::AlphaMode;pub use presentation::BasicMaterial;pub use presentation::GltfMaterial;pub use presentation::Material;pub use presentation::NodePresentation;pub use presentation::NormalTexture;pub use presentation::OcclusionTexture;pub use presentation::Visibility;pub use scene::Bounds;pub use scene::GeometryKind;pub use scene::GeometryRef;pub use scene::Instance;pub use scene::LineBuffer;pub use scene::MeshBuffer;pub use scene::Origin;pub use scene::PointBuffer;pub use scene::RenderScene;pub use scene::SceneOptions;pub use scene::SceneWarning;pub use scene::SceneWarningKind;pub use transform::world_from_parent;pub use transform::Transform;
Modules§
- curves
- Polylines from
usd::usdgeom::basiscurves. - error
- The error shared by every attribute decoder in this crate.
- glb
- Binary glTF 2.0 (GLB) export of a
RenderScene. - math
- Small vector helpers shared by the decoders.
- mesh
- Indexed triangle meshes from
usd::usdgeom::mesh. - points
- Point clouds from
points::array,points::base64, andpcd::base64(ifcx_alpha). - presentation
- Visibility, colour, opacity, and glTF PBR materials (
ifcx_alpha). - scene
- A flat, renderer-neutral render scene over a composed node tree.
- transform
- Local and world transforms from
usd::xformop.
Traits§
- Attributes
- A node’s attributes keyed by namespaced attribute id, as in a file’s
schemas(for examplepoints::arrayorgltf::material).