Skip to main content

Compound Shapes

OCCT category icon with a stylized logo representation

Compound shapes are one of the most powerful features in OCCT that allow you to group multiple geometric entities into a single cohesive unit. They serve as containers that can hold any combination of OCCT shape types - wires, edges, faces, shells, and solids - treating them as one unified entity.

What Are Compound Shapes?

A compound is essentially a collection of shapes that behave as a single OCCT shape object. Think of it as a group in a drawing application, but with much more sophisticated geometric capabilities. When you create a compound, you're not merging the geometries like with boolean operations - instead, you're creating a hierarchical structure that maintains individual shape identities while enabling collective operations.

This grouping mechanism is particularly valuable when working with complex assemblies, repetitive patterns, or when you need to apply transformations to multiple objects simultaneously. Compounds preserve the original topology of each constituent shape while providing the convenience of single-entity manipulation.

Key Benefits of Using Compounds

Performance Optimization: One of the most significant advantages of compounds is their impact on rendering performance. When you have many individual shapes, each one requires its own mesh generation and GPU draw call. Compounds in Bitbybit consolidate these into a single mesh, dramatically reducing the computational overhead and improving frame rates.

Unified Transformations: Compounds allow you to treat multiple shapes as a single entity for transformations. Whether you're rotating, translating, scaling, or applying complex transformations, all constituent shapes move together as one cohesive unit. This eliminates the need to individually transform each shape and ensures perfect synchronization.

Simplified Organization: In complex models with hundreds or thousands of individual elements, compounds provide a natural organizational structure. You can group related shapes logically, making your code more maintainable and your geometric operations more intuitive.

Memory Efficiency: By grouping shapes into compounds, you reduce the overhead associated with managing individual shape references, leading to more efficient memory usage in large-scale applications.

Performance Problem: Individual Shape Creation

When creating multiple similar shapes individually, you encounter significant performance bottlenecks. Each shape requires separate mesh generation, individual GPU draw calls, and independent memory allocation. This becomes particularly problematic when working with patterns or arrays of objects.

The example below demonstrates this performance issue by creating individual spheres in a 3D grid pattern. Notice how each sphere is created and rendered separately, leading to reduced performance and slower frame rates as the number of objects increases.

Performance Testing

If you're not experiencing noticeable performance issues in the first example, try increasing the grid size substantially (to 8 or 10) to see the difference. The performance impact becomes much more apparent with larger numbers of objects.

Bitbybit Platform

Creating individual spheres leads to performance issues

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"b446c4e9ffd24726": {
"id": "b446c4e9ffd24726",
"name": "bitbybit.vector.span",
"customName": "span",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 2.5,
"min": -10,
"max": 1
},
"inputs": {
"min": {
"connections": [
{
"node": "f88fd357ced411f1",
"output": "result",
"data": {}
}
]
},
"max": {
"connections": [
{
"node": "c9ddf3d81304fa53",
"output": "result",
"data": {}
}
]
}
},
"position": [
1033.7463569641113,
513.0007019042969
]
},
"c9ddf3d81304fa53": {
"id": "c9ddf3d81304fa53",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 2,
"max": 10,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 5
},
"inputs": {},
"position": [
-58.33047223289259,
628.7886361749063
]
},
"f88fd357ced411f1": {
"id": "f88fd357ced411f1",
"name": "bitbybit.math.negate",
"customName": "negate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 1
},
"inputs": {
"number": {
"connections": [
{
"node": "c9ddf3d81304fa53",
"output": "result",
"data": {}
}
]
}
},
"position": [
546.3032722473145,
366.40267944382504
]
},
"6c01c1c47ff8a874": {
"id": "6c01c1c47ff8a874",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"x": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
},
"y": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
},
"z": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
}
},
"position": [
1771.9867359310028,
470.02919755656137
]
},
"c509b5aced40b98d": {
"id": "c509b5aced40b98d",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "b446c4e9ffd24726",
"output": "result",
"data": {}
}
]
}
},
"position": [
1402.6814793938981,
548.4041387968635
]
},
"859b8e895567d5fd": {
"id": "859b8e895567d5fd",
"name": "bitbybit.occt.shapes.solid.createSphere",
"customName": "sphere",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 1,
"center": [
0,
0,
0
]
},
"inputs": {
"center": {
"connections": [
{
"node": "6c01c1c47ff8a874",
"output": "result",
"data": {}
}
]
}
},
"position": [
2142.757180037668,
427.66801356001173
]
}
}
}

Solution: Creating Compounds for Better Performance

The solution to this performance problem is to use compounds. Instead of creating individual shapes that are rendered separately, you create all the shapes first and then combine them into a single compound. This compound is then treated as one entity for rendering purposes, dramatically improving performance.

Bitbybit Platform

Compounded spheres provide significantly better performance

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"b446c4e9ffd24726": {
"id": "b446c4e9ffd24726",
"name": "bitbybit.vector.span",
"customName": "span",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 2.5,
"min": -10,
"max": 1
},
"inputs": {
"min": {
"connections": [
{
"node": "f88fd357ced411f1",
"output": "result",
"data": {}
}
]
},
"max": {
"connections": [
{
"node": "c9ddf3d81304fa53",
"output": "result",
"data": {}
}
]
}
},
"position": [
1033.7463569641113,
513.0007019042969
]
},
"c9ddf3d81304fa53": {
"id": "c9ddf3d81304fa53",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 2,
"max": 10,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 5
},
"inputs": {},
"position": [
-58.33047223289259,
628.7886361749063
]
},
"f88fd357ced411f1": {
"id": "f88fd357ced411f1",
"name": "bitbybit.math.negate",
"customName": "negate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 1
},
"inputs": {
"number": {
"connections": [
{
"node": "c9ddf3d81304fa53",
"output": "result",
"data": {}
}
]
}
},
"position": [
546.3032722473145,
366.40267944382504
]
},
"6c01c1c47ff8a874": {
"id": "6c01c1c47ff8a874",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"x": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
},
"y": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
},
"z": {
"connections": [
{
"node": "c509b5aced40b98d",
"output": "result",
"data": {}
}
]
}
},
"position": [
1771.9867359310028,
470.02919755656137
]
},
"c509b5aced40b98d": {
"id": "c509b5aced40b98d",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "b446c4e9ffd24726",
"output": "result",
"data": {}
}
]
}
},
"position": [
1402.6814793938981,
548.4041387968635
]
},
"859b8e895567d5fd": {
"id": "859b8e895567d5fd",
"name": "bitbybit.occt.shapes.solid.createSphere",
"customName": "sphere",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 1,
"center": [
0,
0,
0
]
},
"inputs": {
"center": {
"connections": [
{
"node": "6c01c1c47ff8a874",
"output": "result",
"data": {}
}
]
}
},
"position": [
2142.757180037668,
427.66801356001173
]
},
"b33c2e10e390804f": {
"id": "b33c2e10e390804f",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "859b8e895567d5fd",
"output": "result",
"data": {}
}
]
}
},
"position": [
2517.4087816268816,
468.10613836610617
]
},
"1c25083cf4fbd5d8": {
"id": "1c25083cf4fbd5d8",
"name": "bitbybit.occt.shapes.compound.makeCompound",
"customName": "make compound",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shapes": {
"connections": [
{
"node": "b33c2e10e390804f",
"output": "list",
"data": {}
}
]
}
},
"position": [
2897.9006903391196,
427.5889225632506
]
}
}
}

Unified Transformations: Moving Compounds as Single Entities

Another major advantage of compounds is the ability to transform the entire group as a single entity. When you rotate a compound, all constituent shapes move together in perfect synchronization. This eliminates the complexity of managing individual transformations for each shape and demonstrates how compounds maintain their internal relationships during transformations.

Bitbybit Platform

Compound can be rotated and translated as a single grouped entity

rete logoRete
Script Source (rete)
{
"id": "rete-v2-json",
"nodes": {
"b446c4e9ffd24726": {
"id": "b446c4e9ffd24726",
"name": "bitbybit.vector.span",
"customName": "span",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"step": 2.5,
"min": -10,
"max": 1
},
"inputs": {
"min": {
"connections": [
{
"node": "f88fd357ced411f1",
"output": "result",
"data": {}
}
]
},
"max": {
"connections": [
{
"node": "31426ff201881699",
"output": "result",
"data": {}
}
]
}
},
"position": [
1033.7463569641113,
513.0007019042969
]
},
"31426ff201881699": {
"id": "31426ff201881699",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 2,
"max": 10,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 5
},
"inputs": {},
"position": [
-58.33047223289259,
628.7886361749063
]
},
"f88fd357ced411f1": {
"id": "f88fd357ced411f1",
"name": "bitbybit.math.negate",
"customName": "negate",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"number": 1
},
"inputs": {
"number": {
"connections": [
{
"node": "31426ff201881699",
"output": "result",
"data": {}
}
]
}
},
"position": [
546.3032722473145,
366.40267944382504
]
},
"6c01c1c47ff8a874": {
"id": "6c01c1c47ff8a874",
"name": "bitbybit.point.pointXYZ",
"customName": "point xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 0,
"z": 0
},
"inputs": {
"x": {
"connections": [
{
"node": "bacbbb6931b036ab",
"output": "result",
"data": {}
}
]
},
"y": {
"connections": [
{
"node": "bacbbb6931b036ab",
"output": "result",
"data": {}
}
]
},
"z": {
"connections": [
{
"node": "bacbbb6931b036ab",
"output": "result",
"data": {}
}
]
}
},
"position": [
1771.9867359310028,
470.02919755656137
]
},
"bacbbb6931b036ab": {
"id": "bacbbb6931b036ab",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "b446c4e9ffd24726",
"output": "result",
"data": {}
}
]
}
},
"position": [
1402.6814793938981,
548.4041387968635
]
},
"859b8e895567d5fd": {
"id": "859b8e895567d5fd",
"name": "bitbybit.occt.shapes.solid.createSphere",
"customName": "sphere",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 1,
"center": [
0,
0,
0
]
},
"inputs": {
"center": {
"connections": [
{
"node": "6c01c1c47ff8a874",
"output": "result",
"data": {}
}
]
}
},
"position": [
2142.757180037668,
427.66801356001173
]
},
"0e366b3b840415bd": {
"id": "0e366b3b840415bd",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "859b8e895567d5fd",
"output": "result",
"data": {}
}
]
}
},
"position": [
2517.4087816268816,
468.10613836610617
]
},
"1c25083cf4fbd5d8": {
"id": "1c25083cf4fbd5d8",
"name": "bitbybit.occt.shapes.compound.makeCompound",
"customName": "make compound",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shapes": {
"connections": [
{
"node": "0e366b3b840415bd",
"output": "list",
"data": {}
}
]
}
},
"position": [
2897.9006903391196,
427.5889225632506
]
},
"03199bba6f897964": {
"id": "03199bba6f897964",
"name": "bitbybit.occt.transforms.rotate",
"customName": "rotate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"axis": [
0,
0,
1
],
"angle": 45
},
"inputs": {
"shape": {
"connections": [
{
"node": "1c25083cf4fbd5d8",
"output": "result",
"data": {}
}
]
}
},
"position": [
3290.919250683614,
427.358216136201
]
}
}
}

Applications and Best Practices

Compounds are particularly valuable in several scenarios:

Assembly Management: When working with mechanical assemblies, architectural models, or any complex structure with multiple components, compounds provide a natural hierarchy for organization and manipulation.

Performance Optimization: For applications requiring real-time interaction with many objects, compounds dramatically reduce the computational overhead of rendering and transforming multiple shapes.

Parametric Design: In parametric workflows where you need to generate multiple variations of pattern-based designs, compounds allow you to treat complex patterns as single entities for easy modification.

Animation and Simulation: When animating multiple objects that need to move together, compounds ensure perfect synchronization without the complexity of coordinating individual transformations.

When implementing compounds in your projects, consider grouping logically related shapes, maintaining reasonable compound sizes for optimal performance, and using nested compounds for hierarchical organization when dealing with very complex assemblies. The examples above demonstrate the fundamental patterns that scale effectively from simple arrays to complex industrial applications.