IFC is a standard format for storing building information models (BIM). It is used in the architecture, engineering and construction (AEC) industry.
It’s an open, vendor-neutral and non-proprietary format, which means everyone has access to the full specification how everything should work and everyone can implement it. And it is supported by a lot of software:
If you want to learn more about the IFC format, follow these links:
Various IFC overviews:
Official documentation and standards:
IFC 4.3 specification (latest), this is what we implement. This is not an easy read (and you don’t need to read it all), but this is the ultimate source of knowledge about IFC.
We like open 3D standards in Castle Game Engine (Michalis is preaching about his love for glTF and X3D at various conferences) so IFC naturally joins our capabilities.
First of all, you can just open any supported IFC file with any of our tools. Like this:
Get or make a sample IFC file:
For example take one of the testcases from Community-Sample-Test-Files for IFC 4.x. Rename the file from .json
→ .ifcjson
.
Or create IFC file using Blender and BonsaiBIM add-on, a great add-on that turns Blender into a full-featured IFC editor. Save the IFC to .ifcjson
format.
Or convert any IFC in STEP format (.ifc
) to IFC in JSON format (.ifcjson
) using Python conversion scripts (our fork with some fixes).
Then open it using Castle Model Viewer.
Check out the dedicated example using IFC classes to add and modify walls, that can load, save and display IFC models. It’s in the examples/ifc/ directory of the engine sources.
We can load and save the IFC entities listed in API docs of CastleIfc
unit. This includes over 100 classes reflecting the IFC specification.
All the defined IFC entities can be loaded and saved to IFC files in the JSON encoding, with the .ifcjson
extension.
Note
|
We require to use .ifcjson extension for IFC files in JSON encoding, not just .json . That’s because we also support another popular format, Spine animations, that uses .json extension.
|
Note
|
If you’re looking for conversion between .ifcjson and .ifc (STEP encoding), you can use the Python conversion scripts (our fork with some fixes).
|
We convert a lot of "presentational" IFC entities to X3D nodes and display them.
A lot of IFC content is just "metadata" for our engine, that is: we load and save it, and you can use it from Pascal (by looking at IFC classes properties, or by looking at X3D nodes metadata like MyGroup.MetadataString['IFC_Name']
, MyGroup.MetadataString['IFC_Description']
). But it doesn’t affect the display in any way.
We load various IFC containers and lists to the corresponding X3D TGroupNode
.
The transformation hierarchy (following TIfcObjectPlacement
including TIfcObjectPlacement.PlacementRelTo
) is expressed using X3D TTransformNode
.
We display these 3D shape entities:
lines: TIfcPolyline
in IFC, TLineSetNode
in X3D
indexed lines: TIfcIndexedPolyCurve
in IFC, TIndexedLineSetNode
in X3D
extrusion of a cross-section along a direction: TIfcExtrudedAreaSolid
in IFC, TExtrusionNode
in X3D
mesh: TIfcPolygonalFaceSet
in IFC, TIndexedFaceSetNode
in X3D
Our conversion from IFC to X3D allows to display IFC models using Castle Game Engine (using TCastleScene
) and allows to literally convert between model formats, from IFC to any format we can save (X3D, STL, and soon glTF).
X3D nodes can be mapped back to IFC classes, which is useful e.g. for picking 3D objects using mouse. Castle Game Engine has APIs to determine what X3D node has been picked, and then you can map it back to an IFC "product" (like a wall, a window, a door) using TCastleIfcMapping.NodeToProduct
.
We define some utility methods to operate on IFC classes:
TIfcProduct.AddMeshRepresentation
, TIfcProduct.AddBoxRepresentation
(adding meshes to products)
TIfcProduct.RelativePlacement
(move products)
TIfcObjectDefinition.AddIsDecomposedBy
, TIfcProject.BestContainer
(relationship between larger spatial elements)
TIfcSpatialElement.AddContainedElement
, TIfcSpatialElement.GetContainedElements
(relationship to add elements (products) inside larger spatial elements)
TIfcProject.SetupUnits
(setup standard (metric) units for the project)
TIfcFile.Project
(the main project of the IFC file)
TIfcProject.ModelContext
, TIfcProject.PlanContext
, TIfcProject.SetupModelContext
(querying and creation of geometric contexts, necessary to designate things to be visible in "3D model view" or "2D plan" view).
These utility methods provide easy API to perform common operations, like adding and moving elements represented by transformed meshes. These utilities are not strictly necessary to build/modify IFC content, but they make some usage simpler.
Examples:
See lower on this page for example usage of these methods to easily add walls and floors.
Our example examples/ifc/ shows the usage of these methods to make a small IFC editor in Castle Game Engine, that can load, save and display IFC models. The created IFC files can be then opened in other IFC tools, like BonsaiBIM or FreeCAD.
Note
|
Let us know if you need more features related to IFC. Bug reports and PRs are welcome, as well as donations toward the IFC support, we’re happy to provide commercial support for companies too. We’re committed to IFC support. Michalis talks at conferences how he loves open 3D standards --- well, IFC is one of them! |
The IFC files saved by our engine can be opened back in other IFC tools like BonsaiBIM and FreeCAD (after conversion from IFC JSON to STEP using Python conversion scripts). They work regardless if you build IFC structure from scratch in our engine or load + modify some existing IFC model.
This allows to develop a specialized IFC tools in Castle Game Engine that can be used in the IFC ecosystem. We can consume and produce IFC files that "play well" with other software, and everything "thinks" using IFC classes.
To test this, IFC files produced by our example examples/ifc/ can be verified to look the same in BonsaiBIM and FreeCAD:
Note
|
Above, we added some lights for display in our engine, just to make it look fancy :) These are not part of the IFC standard. There are other graphic features in our engine you could use, like shadows using shadow volumes, tweaking MyScene.RenderOptions.WireframeEffect .
|
Basically, you don’t need to learn anything new to use IFC with Castle Game Engine.
Load a sample IFC file:
using the TCastleSceneCore.Load
method,
or by setting TCastleSceneCore.Url
property to the IFC file.
Just follow the manual page about viewports and scenes and subsequent pages about TCastleScene
usage.
You can also use the LoadNode
method to load
TX3DRootNode
instance, without the need for a full TCastleScene
. This makes sense if you don’t need to display the model at all.
Note
|
The IFC files follow the convention of "Z axis is up". This is different to Castle Game Engine convention (consistent with glTF, X3D, and some other game engines) of "Y axis is up". Sometimes you can just ignore this difference. Everything works. Just setup your camera to look natural with "Z up". But for most projects, we advise to display IFC models to follow the "Y up" convention. This will make e.g. physics works in natural way (our gravity pulls down in -Y by default). And it will make IFC models match glTF and X3D models better. To do this you can rotate the |
There is another way to use IFC support that allows you to utilize the full power of IFC and work directly with IFC classes. All IFC entities and other types are expressed as natural Pascal classes, enums etc.
In contrast to the approach described in the previous section ("Loading and saving IFC in TCastleScene"), where you load and save IFC files but your "single source of truth" about the model is the state of TCastleScene
(which means: set of X3D nodes), in this new approach your "single source of truth" is your hierarchy of IFC classes. This approach is also called "native BIM" by various tools in the IFC ecosystem.
The advantage of this approach is that you work with the IFC concepts directly. You can modify the IFC data, and make the displayed scene to reflect the changes. So:
You use classes from CastleIfc
unit, following exactly the same concepts and names as the IFC specification.
You don’t wonder "how this metadata was mapped to X3D node" because you don’t need to inspect X3D nodes to investigate what’s inside the IFC file.
Round-trip (read IFC, save it back) preserves exactly the input. Because you keep the TIfcFile
instance existing. You load to TIfcFile
, keep it and modify it, then save it back to file.
In contrast, when working only with TX3DRootNode
and discarding the IFC-native information, the writer has to create new IFC data from X3D nodes, inside X3DToIfc
.
This necessarily "drops" some information (otherwise we’d need to replicate all the IFC information using only X3D metadata, which would be a big work given lots of IFC classes and concepts that are hard to transfer both ways like IFC PlacementRelTo
; and it would likely be unnecessary work — since people who want to use IFC natively are better served by just using IFC classes from Pascal).
To follow this approach, load IFC files using IfcJsonLoad
:
var
IfcFile: TIfcFile;
begin
IfcFile := IfcJsonLoad('castle-data:/my_file.ifcjson');
// ...
end;
and then operate on the loaded IfcFile
, exploring the properties of TIfcFile
and everything inside, rooted in TIfcFile.Project
. The documentation of all the IFC classes is part of our API documentation: see CastleIfc
.
Inspect and modify the properties of IFC classes as you wish. At one point, you can:
Save to result back to file using IfcJsonSave
. Like this:
IfcJsonSave(IfcFile, 'output.ifcjson');
Convert the IFC to a set of X3D nodes (to display them using TCastleScene
) using IfcToX3D
. If you only want to do it once, do it like this (but if you want to do it multiple times, read next point):
var
MyRoot: TX3DRootNode;
begin
MyRoot := IfcToX3D(IfcFile);
MyScene.Load(MyRoot, true);
end;
You can also load and then efficiently update multiple times the displayed scene (update display each time when you change the IFC classes).
This is done by using TCastleIfcMapping
class. Like this:
var
IfcFile: TIfcFile;
IfcMapping: TCastleIfcMapping;
Wall: TIfcWall;
begin
IfcFile := IfcFromJson('castle-data:/my_file.ifcjson');
try
IfcMapping := TCastleIfcMapping.Create;
try
// convert IfcFile to X3D, in a way that allows to efficiently update it later
IfcMapping.Load(IfcFile, 'castle-data:/');
// display the result using MyScene:TCastleScene; it will own the IfcMapping.RootNode
MyScene.Load(IfcMapping.RootNode, true);
// modify IfcFile, e.g. add a new wall
Wall := TIfcWall.Create(IfcFile);
Wall.AddBoxRepresentation(IfcFile.Project.ModelContext,
Box3D(
Vector3(0, 0, 0),
Vector3(10, 0.5, 2) // Z is "up", by convention, in IFC
));
IfcFile.Project.BestContainer.AddContainedElement(Wall);
// modify the contents of RootNode, to reflect above new wall.
// the MyScene displaying it will automatically reflect the changes
IfcMapping.Update(IfcFile);
finally FreeAndNil(IfcMapping) end;
finally FreeAndNil(IfcFile) end;
end;
Consult the examples/ifc/ example application (in the engine sources) for a full code following this approach.
This work has been sponsored by the Sorpetaler Fensterbau GmbH company. Thank you!
To improve this documentation just edit this page and create a pull request to cge-www repository.