Compounded Drawing
Building on the fundamental concepts from the compound shapes introduction, this tutorial demonstrates how to apply compound techniques to complex, real-world scenarios. We'll explore a sophisticated example that creates a parametric hexagonal pattern on a curved surface, showing how compounds dramatically improve rendering performance while enabling organized management of complex geometries.
The Challenge: Complex Parametric Patterns
When working with parametric designs that generate hundreds or thousands of individual geometric elements, performance becomes critical. Consider a scenario where you need to create a hexagonal frame pattern across a curved surface - each hexagon consists of multiple faces, wires, and edges that would normally require individual rendering calls.
Without compounds, such patterns would overwhelm the graphics pipeline with separate draw calls for each element. The solution lies in strategically grouping related elements into compounds before rendering, transforming what could be thousands of individual operations into just a few efficient compound draws.
Advanced Compound Application: Hexagonal Surface Pattern
The example below demonstrates this principle through a complex workflow that creates a parametric hexagonal pattern on a lofted surface. This real-world scenario showcases several advanced compound techniques:
Surface Creation: First, we generate a complex curved surface by lofting between three interpolated wire curves with different point configurations.
Pattern Generation: The surface is subdivided into hexagonal patterns using two different scaling approaches - one regular and one scaled - creating complementary geometric sets.
Strategic Grouping: Rather than rendering each hexagonal frame individually, we use pattern filtering to group frames into logical sets, then create separate compounds for each group.
Efficient Rendering: Finally, we render only two compound entities instead of potentially hundreds of individual faces, with different materials applied to each compound group.
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"bottomwire": {
"id": "bottomwire",
"name": "bitbybit.occt.shapes.wire.interpolatePoints",
"customName": "bottom wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"periodic": false,
"tolerance": 0.1
},
"inputs": {
"points": {
"connections": [
{
"node": "09aaa33913f67046",
"output": "result",
"data": {}
}
]
}
},
"position": [
804.3759428936219,
255.41502016627993
]
},
"middlewire": {
"id": "middlewire",
"name": "bitbybit.occt.shapes.wire.interpolatePoints",
"customName": "middle wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"periodic": false,
"tolerance": 0.1
},
"inputs": {
"points": {
"connections": [
{
"node": "c7e788a8b84974ea",
"output": "result",
"data": {}
}
]
}
},
"position": [
800,
600
]
},
"topwire": {
"id": "topwire",
"name": "bitbybit.occt.shapes.wire.interpolatePoints",
"customName": "top wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"periodic": false,
"tolerance": 0.1
},
"inputs": {
"points": {
"connections": [
{
"node": "4923cc4b9415e46a",
"output": "result",
"data": {}
}
]
}
},
"position": [
801.717534733165,
951.8166792524057
]
},
"5885a89725e9fbe0": {
"id": "5885a89725e9fbe0",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "bottomwire",
"output": "result",
"data": {}
},
{
"node": "middlewire",
"output": "result",
"data": {}
},
{
"node": "topwire",
"output": "result",
"data": {}
}
]
}
},
"position": [
1200,
600
]
},
"loftface": {
"id": "loftface",
"name": "bitbybit.occt.operations.loft",
"customName": "loft surface",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"makeSolid": false
},
"inputs": {
"shapes": {
"connections": [
{
"node": "5885a89725e9fbe0",
"output": "list",
"data": {}
}
]
}
},
"position": [
1595.0487702041482,
559.6926796377796
]
},
"f9dbfe1c98680d76": {
"id": "f9dbfe1c98680d76",
"name": "bitbybit.occt.shapes.face.getFace",
"customName": "get face",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"index": 0
},
"inputs": {
"shape": {
"connections": [
{
"node": "loftface",
"output": "result",
"data": {}
}
]
}
},
"position": [
1980.2487300409268,
559.7041116519489
]
},
"17be61c967bdbffc": {
"id": "17be61c967bdbffc",
"name": "bitbybit.occt.shapes.face.subdivideToHexagonWires",
"customName": "subdivide to hexagon wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"nrHexagonsU": 10,
"nrHexagonsV": 10,
"flatU": false,
"offsetFromBorderU": 0,
"offsetFromBorderV": 0,
"extendUUp": false,
"extendUBottom": false,
"extendVUp": false,
"extendVBottom": false
},
"inputs": {
"shape": {
"connections": [
{
"node": "f9dbfe1c98680d76",
"output": "result",
"data": {}
}
]
},
"nrHexagonsU": {
"connections": [
{
"node": "0367a65ba902b339",
"output": "result",
"data": {}
}
]
},
"nrHexagonsV": {
"connections": [
{
"node": "f568f51be48df32f",
"output": "result",
"data": {}
}
]
}
},
"position": [
2490.036274919156,
553.9247536340029
]
},
"02937902d77e3099": {
"id": "02937902d77e3099",
"name": "bitbybit.occt.shapes.face.subdivideToHexagonWires",
"customName": "subdivide to hexagon wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"nrHexagonsU": 10,
"nrHexagonsV": 10,
"flatU": false,
"offsetFromBorderU": 0,
"offsetFromBorderV": 0,
"extendUUp": false,
"extendUBottom": false,
"extendVUp": false,
"extendVBottom": false
},
"inputs": {
"shape": {
"connections": [
{
"node": "f9dbfe1c98680d76",
"output": "result",
"data": {}
}
]
},
"nrHexagonsU": {
"connections": [
{
"node": "0367a65ba902b339",
"output": "result",
"data": {}
}
]
},
"scalePatternV": {
"connections": [
{
"node": "b3d925482eba7c1d",
"output": "result",
"data": {}
}
]
},
"scalePatternU": {
"connections": [
{
"node": "b3d925482eba7c1d",
"output": "result",
"data": {}
}
]
},
"nrHexagonsV": {
"connections": [
{
"node": "f568f51be48df32f",
"output": "result",
"data": {}
}
]
}
},
"position": [
2485.953782467995,
1370.418357408917
]
},
"bbe58b7a15d92c2f": {
"id": "bbe58b7a15d92c2f",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "02937902d77e3099",
"output": "result",
"data": {}
}
]
}
},
"position": [
2859.4256379145177,
1411.0019530979657
]
},
"f9e0d2238290f7f7": {
"id": "f9e0d2238290f7f7",
"name": "bitbybit.occt.shapes.wire.reversedWire",
"customName": "reversed wire",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"shape": {
"connections": [
{
"node": "bbe58b7a15d92c2f",
"output": "result",
"data": {}
}
]
}
},
"position": [
3225.9296811342447,
1372.4776309555743
]
},
"316fd1d3d87b256f": {
"id": "316fd1d3d87b256f",
"name": "bitbybit.occt.shapes.face.createFaceFromWires",
"customName": "face from wires",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"planar": false
},
"inputs": {
"shapes": {
"connections": [
{
"node": "ab81430e8cb96958",
"output": "result",
"data": {}
}
]
}
},
"position": [
5112.912404370474,
1051.6631227938249
]
},
"67068806a2d1259e": {
"id": "67068806a2d1259e",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "f9e0d2238290f7f7",
"output": "result",
"data": {}
}
]
}
},
"position": [
3587.3344654899656,
1409.037231519246
]
},
"0e0d2df57073ad69": {
"id": "0e0d2df57073ad69",
"name": "bitbybit.lists.flipLists",
"customName": "flip lists",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"clone": true
},
"inputs": {
"list": {
"connections": [
{
"node": "da45c87c0cad7573",
"output": "list",
"data": {}
}
]
}
},
"position": [
4369.400631061372,
1081.305088555142
]
},
"da45c87c0cad7573": {
"id": "da45c87c0cad7573",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "17be61c967bdbffc",
"output": "result",
"data": {}
},
{
"node": "67068806a2d1259e",
"output": "list",
"data": {}
}
]
}
},
"position": [
3999.3386274573427,
1121.9828766382495
]
},
"ab81430e8cb96958": {
"id": "ab81430e8cb96958",
"name": "bitbybit.lists.flatten",
"customName": "flatten",
"data": {
"nrLevels": 1
},
"inputs": {
"list": {
"connections": [
{
"node": "0e0d2df57073ad69",
"output": "result",
"data": {}
}
]
}
},
"position": [
4736.0567498732935,
1117.8968252406555
]
},
"f8d0dc03aa2b2ac4": {
"id": "f8d0dc03aa2b2ac4",
"name": "bitbybit.text.areaCreate",
"customName": "text area",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"options": {
"width": 292,
"height": 35
},
"text": "[[-30, 0, -20], [-10, 0, 0], [0, 0, 10], [10, 0, 0],[30, 0, -20]]\n\n"
},
"inputs": {},
"position": [
42.38544650004519,
260.68610662806805
]
},
"a1351efae39cf796": {
"id": "a1351efae39cf796",
"name": "bitbybit.text.areaCreate",
"customName": "text area",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"options": {
"width": 284,
"height": 32
},
"text": "[[-20, 20, -10], [-5, 20, 15], [0, 20, 20], [5, 20, 15],[20, 20, -10]]\n\n"
},
"inputs": {},
"position": [
45.653379576308,
603.3144633544662
]
},
"c7e788a8b84974ea": {
"id": "c7e788a8b84974ea",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[0, 0, 0]"
},
"inputs": {
"text": {
"connections": [
{
"node": "a1351efae39cf796",
"output": "result",
"data": {}
}
]
}
},
"position": [
427.9731290182838,
601.4072961194012
]
},
"09aaa33913f67046": {
"id": "09aaa33913f67046",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[0, 0, 0]"
},
"inputs": {
"text": {
"connections": [
{
"node": "f8d0dc03aa2b2ac4",
"output": "result",
"data": {}
}
]
}
},
"position": [
439.2109544164346,
260.0904145164821
]
},
"88ad8cfc1367b146": {
"id": "88ad8cfc1367b146",
"name": "bitbybit.text.areaCreate",
"customName": "text area",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"options": {
"width": 242,
"height": 30
},
"text": "[[-15, 30, 0], [-5, 30, 5], [0, 30, 10], [5, 30, 5],[15, 30, 0]]\n\n"
},
"inputs": {},
"position": [
56.36380730589735,
960.4638852035587
]
},
"4923cc4b9415e46a": {
"id": "4923cc4b9415e46a",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[0, 0, 0]"
},
"inputs": {
"text": {
"connections": [
{
"node": "88ad8cfc1367b146",
"output": "result",
"data": {}
}
]
}
},
"position": [
427.04410360712416,
957.5124738568434
]
},
"8189bc84029d30af": {
"id": "8189bc84029d30af",
"name": "bitbybit.lists.createList",
"customName": "create list",
"data": {},
"inputs": {
"listElements": {
"connections": [
{
"node": "316fd1d3d87b256f",
"output": "result",
"data": {}
}
]
}
},
"position": [
5520.546804372246,
1083.580155421671
]
},
"8915debdbefaef77": {
"id": "8915debdbefaef77",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"options": {
"connections": [
{
"node": "ecd00106b8d42973",
"output": "result",
"data": {}
}
]
},
"entity": {
"connections": [
{
"node": "d5861077d4424f64",
"output": "result",
"data": {}
}
]
}
},
"position": [
7858.947647642291,
1516.5912829621361
]
},
"8f0e43d996ce2eb7": {
"id": "8f0e43d996ce2eb7",
"name": "bitbybit.babylon.scene.enableSkybox",
"customName": "enable skybox",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"skybox": "city",
"size": 1000,
"blur": 0.1,
"environmentIntensity": 0.7,
"hideSkybox": true
},
"inputs": {},
"position": [
1330.016240926373,
3921.8377573989997
]
},
"0367a65ba902b339": {
"id": "0367a65ba902b339",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 10,
"max": 30,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 28
},
"inputs": {},
"position": [
107.64800114272066,
1452.3963806505471
]
},
"b3d925482eba7c1d": {
"id": "b3d925482eba7c1d",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[0.7]"
},
"inputs": {},
"position": [
2006.2758597691181,
1349.6087847915644
]
},
"f568f51be48df32f": {
"id": "f568f51be48df32f",
"name": "bitbybit.math.numberSlider",
"customName": "number slider",
"data": {
"options": {
"min": 10,
"max": 30,
"step": 1,
"width": 350,
"updateOnDrag": false
},
"number": 10
},
"inputs": {},
"position": [
93.72338722042218,
1622.754313570655
]
},
"4c586ec9c4ab3043": {
"id": "4c586ec9c4ab3043",
"name": "bitbybit.babylon.material.pbrMetallicRoughness.create",
"customName": "pbr metallic roughness",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"name": "Custom Material",
"baseColor": "#9a57ff",
"emissiveColor": "#000000",
"metallic": 0.1,
"roughness": 0.9,
"alpha": 1,
"backFaceCulling": false,
"zOffset": 2
},
"inputs": {},
"position": [
6839.387051047384,
2267.7088364430565
]
},
"ecd00106b8d42973": {
"id": "ecd00106b8d42973",
"name": "bitbybit.draw.optionsOcctShapeMaterial",
"customName": "options occt shape material",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"precision": 0.01,
"drawEdges": true,
"edgeColour": "#000000",
"edgeWidth": 10
},
"inputs": {
"faceMaterial": {
"connections": [
{
"node": "4c586ec9c4ab3043",
"output": "result",
"data": {}
}
]
}
},
"position": [
7212.179378860794,
2229.5471681797653
]
},
"6cc3ec2270f0f390": {
"id": "6cc3ec2270f0f390",
"name": "bitbybit.babylon.scene.adjustActiveArcRotateCamera",
"customName": "adjust active arc rotate camera",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"position": [
10,
10,
10
],
"lookAt": [
0,
0,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {
"position": {
"connections": [
{
"node": "e4512632da197338",
"output": "result",
"data": {}
}
]
},
"lookAt": {
"connections": [
{
"node": "55b07f2f7d8f577e",
"output": "result",
"data": {}
}
]
}
},
"position": [
1332.5534259486913,
2424.9313448977655
]
},
"e4512632da197338": {
"id": "e4512632da197338",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 44,
"y": 30,
"z": 44
},
"inputs": {},
"position": [
895.8472178437926,
2328.381466574848
]
},
"55b07f2f7d8f577e": {
"id": "55b07f2f7d8f577e",
"name": "bitbybit.vector.vectorXYZ",
"customName": "vector xyz",
"async": false,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"x": 0,
"y": 15,
"z": 0
},
"inputs": {},
"position": [
927.3725883128666,
2681.3055795464165
]
},
"fe7b1b1c90bd0590": {
"id": "fe7b1b1c90bd0590",
"name": "bitbybit.babylon.scene.drawDirectionalLight",
"customName": "draw directional light",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"direction": [
-100,
-100,
-100
],
"intensity": 3,
"diffuse": "#ffffff",
"specular": "#ffffff",
"shadowGeneratorMapSize": 1024,
"enableShadows": true,
"shadowDarkness": 0,
"shadowUsePercentageCloserFiltering": true,
"shadowContactHardeningLightSizeUVRatio": 0.2,
"shadowBias": 0.0001,
"shadowNormalBias": 0.002,
"shadowMaxZ": 1000,
"shadowMinZ": 0
},
"inputs": {},
"position": [
1222.3502318577364,
3179.147253041469
]
},
"239c0e87d6e0cdd4": {
"id": "239c0e87d6e0cdd4",
"name": "bitbybit.babylon.scene.twoColorLinearGradient",
"customName": "two color linear gradient",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"colorFrom": "#050506",
"colorTo": "#627a9d",
"direction": "to top",
"stopFrom": 0,
"stopTo": 100
},
"inputs": {},
"position": [
1327.3963302073716,
1961.9059336308726
]
},
"15c03b332fd55df6": {
"id": "15c03b332fd55df6",
"name": "bitbybit.draw.drawGridMesh",
"customName": "draw grid mesh",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"width": 400,
"height": 400,
"subdivisions": 10,
"majorUnitFrequency": 10,
"minorUnitVisibility": 0.45,
"gridRatio": 0.5,
"opacity": 0.5,
"backFaceCulling": false,
"mainColor": "#ffffff",
"secondaryColor": "#ffffff"
},
"inputs": {},
"position": [
1336.466465987358,
4357.944233774137
]
},
"7d1027a93b5b2619": {
"id": "7d1027a93b5b2619",
"name": "bitbybit.lists.getByPattern",
"customName": "get by pattern",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"pattern": [
true,
true,
false
]
},
"inputs": {
"pattern": {
"connections": [
{
"node": "e9a93cdbdf16819d",
"output": "result",
"data": {}
}
]
},
"list": {
"connections": [
{
"node": "8189bc84029d30af",
"output": "list",
"data": {}
}
]
}
},
"position": [
6821.9547052052885,
902.7806529537286
]
},
"e9a93cdbdf16819d": {
"id": "e9a93cdbdf16819d",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[true, true, false]"
},
"inputs": {},
"position": [
6231.440080230604,
735.9141562600582
]
},
"1f7e28416bd200a8": {
"id": "1f7e28416bd200a8",
"name": "bitbybit.json.parse",
"customName": "parse",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"text": "[false, false, true]"
},
"inputs": {},
"position": [
6226.398722388475,
424.0462857990449
]
},
"6f2f0e0dd03167c5": {
"id": "6f2f0e0dd03167c5",
"name": "bitbybit.lists.getByPattern",
"customName": "get by pattern",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"pattern": [
true,
true,
false
]
},
"inputs": {
"pattern": {
"connections": [
{
"node": "1f7e28416bd200a8",
"output": "result",
"data": {}
}
]
},
"list": {
"connections": [
{
"node": "8189bc84029d30af",
"output": "list",
"data": {}
}
]
}
},
"position": [
6824.268799573109,
576.1749391729782
]
},
"c2deafb81bb08232": {
"id": "c2deafb81bb08232",
"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": "6f2f0e0dd03167c5",
"output": "result",
"data": {}
}
]
}
},
"position": [
7266.34315852178,
572.3471079241745
]
},
"d5861077d4424f64": {
"id": "d5861077d4424f64",
"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": "7d1027a93b5b2619",
"output": "result",
"data": {}
}
]
}
},
"position": [
7272.267298234055,
899.6742737531788
]
},
"c69d6a51b91dbdf8": {
"id": "c69d6a51b91dbdf8",
"name": "bitbybit.draw.drawAnyAsync",
"customName": "draw any async",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"entity": {
"connections": [
{
"node": "c2deafb81bb08232",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "d75a575149ad341e",
"output": "result",
"data": {}
}
]
}
},
"position": [
7857.222309875908,
1152.8397016480505
]
},
"d75a575149ad341e": {
"id": "d75a575149ad341e",
"name": "bitbybit.draw.optionsOcctShapeMaterial",
"customName": "options occt shape material",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"precision": 0.01,
"drawEdges": true,
"edgeColour": "#000000",
"edgeWidth": 10
},
"inputs": {
"faceMaterial": {
"connections": [
{
"node": "eb3040ea87ee07c3",
"output": "result",
"data": {}
}
]
}
},
"position": [
7217.627028488199,
1685.691706959804
]
},
"eb3040ea87ee07c3": {
"id": "eb3040ea87ee07c3",
"name": "bitbybit.babylon.material.pbrMetallicRoughness.create",
"customName": "pbr metallic roughness",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"name": "Custom Material",
"baseColor": "#000000",
"emissiveColor": "#000000",
"metallic": 0.9,
"roughness": 0.23,
"alpha": 1,
"backFaceCulling": false,
"zOffset": 2
},
"inputs": {},
"position": [
6844.143721750346,
1723.6048498848063
]
}
}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="bottomPoints">bottomPoints</variable><variable id="middlePoints">middlePoints</variable><variable id="topPoints">topPoints</variable><variable id="bottomWire">bottomWire</variable><variable id="middleWire">middleWire</variable><variable id="topWire">topWire</variable><variable id="wiresList">wiresList</variable><variable id="loftedSurface">loftedSurface</variable><variable id="mainFace">mainFace</variable><variable id="nrHexagonsU">nrHexagonsU</variable><variable id="nrHexagonsV">nrHexagonsV</variable><variable id="scalePattern">scalePattern</variable><variable id="hexWires1">hexWires1</variable><variable id="hexWires2">hexWires2</variable><variable id="reversedWires">reversedWires</variable><variable id="i">i</variable><variable id="frames">frames</variable><variable id="framesCompound">firstFramesCompound</variable><variable id="F@k=@{Ucm4;)F4yhAd0o">secondFramesCompound</variable><variable id="blueMaterial">material1</variable><variable id="K0A$dz_a?K_Sr(;(R^mV">material2</variable></variables><block type="variables_set" id="setBottomPoints" x="-500" y="-500"><field name="VAR" id="bottomPoints">bottomPoints</field><value name="VALUE"><block type="bitbybit.json.parse" id="w6l$kYg2J6yW{|~8W4!/"><value name="Text"><block type="text" id="AMgQYcj8Rw86YXCYS7Ug"><field name="TEXT">[[-30, 0, -20], [-10, 0, 0], [0, 0, 10], [10, 0, 0],[30, 0, -20]]</field></block></value></block></value><next><block type="variables_set" id="setMiddlePoints"><field name="VAR" id="middlePoints">middlePoints</field><value name="VALUE"><block type="bitbybit.json.parse" id="gl~GKG6wiL8Dl$T+96tT"><value name="Text"><block type="text" id="/`-ntliJ(g2v4CjH{6ES"><field name="TEXT">[[-20, 20, -10], [-5, 20, 15], [0, 20, 20], [5, 20, 15],[20, 20, -10]]</field></block></value></block></value><next><block type="variables_set" id="setTopPoints"><field name="VAR" id="topPoints">topPoints</field><value name="VALUE"><block type="bitbybit.json.parse" id="#SaB2|(T-3I3@#r$%0b-"><value name="Text"><block type="text" id="[oZWpyivn%WzS%)*3M?,"><field name="TEXT">[[-15, 30, 0], [-5, 30, 5], [0, 30, 10], [5, 30, 5],[15, 30, 0]]</field></block></value></block></value><next><block type="variables_set" id="setBottomWire"><field name="VAR" id="bottomWire">bottomWire</field><value name="VALUE"><block type="base_time_await_return" id="awaitBottomWire"><value name="Promise"><block type="bitbybit.occt.shapes.wire.interpolatePoints" id="createBottomWire"><value name="Points"><block type="variables_get" id="getBottomPoints"><field name="VAR" id="bottomPoints">bottomPoints</field></block></value><value name="Periodic"><block type="logic_boolean" id="periodicFalse1"><field name="BOOL">FALSE</field></block></value><value name="Tolerance"><block type="math_number" id="tolerance1"><field name="NUM">0.1</field></block></value></block></value></block></value><next><block type="variables_set" id="setMiddleWire"><field name="VAR" id="middleWire">middleWire</field><value name="VALUE"><block type="base_time_await_return" id="awaitMiddleWire"><value name="Promise"><block type="bitbybit.occt.shapes.wire.interpolatePoints" id="createMiddleWire"><value name="Points"><block type="variables_get" id="getMiddlePoints"><field name="VAR" id="middlePoints">middlePoints</field></block></value><value name="Periodic"><block type="logic_boolean" id="periodicFalse2"><field name="BOOL">FALSE</field></block></value><value name="Tolerance"><block type="math_number" id="tolerance2"><field name="NUM">0.1</field></block></value></block></value></block></value><next><block type="variables_set" id="setTopWire"><field name="VAR" id="topWire">topWire</field><value name="VALUE"><block type="base_time_await_return" id="awaitTopWire"><value name="Promise"><block type="bitbybit.occt.shapes.wire.interpolatePoints" id="createTopWire"><value name="Points"><block type="variables_get" id="getTopPoints"><field name="VAR" id="topPoints">topPoints</field></block></value><value name="Periodic"><block type="logic_boolean" id="periodicFalse3"><field name="BOOL">FALSE</field></block></value><value name="Tolerance"><block type="math_number" id="tolerance3"><field name="NUM">0.1</field></block></value></block></value></block></value><next><block type="variables_set" id="setWiresList"><field name="VAR" id="wiresList">wiresList</field><value name="VALUE"><block type="lists_create_with" id="createWiresList"><mutation items="3"></mutation><value name="ADD0"><block type="variables_get" id="getBottomWire"><field name="VAR" id="bottomWire">bottomWire</field></block></value><value name="ADD1"><block type="variables_get" id="getMiddleWire"><field name="VAR" id="middleWire">middleWire</field></block></value><value name="ADD2"><block type="variables_get" id="getTopWire"><field name="VAR" id="topWire">topWire</field></block></value></block></value><next><block type="variables_set" id="setLoftedSurface"><field name="VAR" id="loftedSurface">loftedSurface</field><value name="VALUE"><block type="base_time_await_return" id="awaitLoft"><value name="Promise"><block type="bitbybit.occt.operations.loft" id="loftOperation"><value name="Shapes"><block type="variables_get" id="getWiresList"><field name="VAR" id="wiresList">wiresList</field></block></value><value name="MakeSolid"><block type="logic_boolean" id="makeSolidFalse"><field name="BOOL">FALSE</field></block></value></block></value></block></value><next><block type="variables_set" id="setMainFace"><field name="VAR" id="mainFace">mainFace</field><value name="VALUE"><block type="base_time_await_return" id="awaitGetFace"><value name="Promise"><block type="bitbybit.occt.shapes.face.getFace" id="getFaceOperation"><value name="Shape"><block type="variables_get" id="getLoftedSurface"><field name="VAR" id="loftedSurface">loftedSurface</field></block></value><value name="Index"><block type="math_number" id="faceIndex"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="variables_set" id="setNrHexU"><field name="VAR" id="nrHexagonsU">nrHexagonsU</field><value name="VALUE"><block type="math_number" id="hexU"><field name="NUM">28</field></block></value><next><block type="variables_set" id="setNrHexV"><field name="VAR" id="nrHexagonsV">nrHexagonsV</field><value name="VALUE"><block type="math_number" id="hexV"><field name="NUM">10</field></block></value><next><block type="variables_set" id="setScalePattern"><field name="VAR" id="scalePattern">scalePattern</field><value name="VALUE"><block type="lists_create_with" id="scalePatternList"><mutation items="1"></mutation><value name="ADD0"><block type="math_number" id="scaleValue"><field name="NUM">0.7</field></block></value></block></value><next><block type="variables_set" id="setHexWires1"><field name="VAR" id="hexWires1">hexWires1</field><value name="VALUE"><block type="base_time_await_return" id="awaitHexWires1"><value name="Promise"><block type="bitbybit.occt.shapes.face.subdivideToHexagonWires" id="subdivideHex1"><value name="Shape"><block type="variables_get" id="getMainFace1"><field name="VAR" id="mainFace">mainFace</field></block></value><value name="NrHexagonsU"><block type="variables_get" id="getNrHexU1"><field name="VAR" id="nrHexagonsU">nrHexagonsU</field></block></value><value name="NrHexagonsV"><block type="variables_get" id="getNrHexV1"><field name="VAR" id="nrHexagonsV">nrHexagonsV</field></block></value><value name="FlatU"><block type="logic_boolean" id="flatUFalse1"><field name="BOOL">FALSE</field></block></value><value name="OffsetFromBorderU"><block type="math_number" id="offsetU1"><field name="NUM">0</field></block></value><value name="OffsetFromBorderV"><block type="math_number" id="offsetV1"><field name="NUM">0</field></block></value><value name="ExtendUUp"><block type="logic_boolean" id="extendUUpFalse1"><field name="BOOL">FALSE</field></block></value><value name="ExtendUBottom"><block type="logic_boolean" id="extendUBottomFalse1"><field name="BOOL">FALSE</field></block></value><value name="ExtendVUp"><block type="logic_boolean" id="extendVUpFalse1"><field name="BOOL">FALSE</field></block></value><value name="ExtendVBottom"><block type="logic_boolean" id="extendVBottomFalse1"><field name="BOOL">FALSE</field></block></value></block></value></block></value><next><block type="variables_set" id="setHexWires2"><field name="VAR" id="hexWires2">hexWires2</field><value name="VALUE"><block type="base_time_await_return" id="awaitHexWires2"><value name="Promise"><block type="bitbybit.occt.shapes.face.subdivideToHexagonWires" id="subdivideHex2"><value name="Shape"><block type="variables_get" id="getMainFace2"><field name="VAR" id="mainFace">mainFace</field></block></value><value name="NrHexagonsU"><block type="variables_get" id="getNrHexU2"><field name="VAR" id="nrHexagonsU">nrHexagonsU</field></block></value><value name="NrHexagonsV"><block type="variables_get" id="getNrHexV2"><field name="VAR" id="nrHexagonsV">nrHexagonsV</field></block></value><value name="FlatU"><block type="logic_boolean" id="flatUFalse2"><field name="BOOL">FALSE</field></block></value><value name="ScalePatternU"><block type="variables_get" id="getScalePattern1"><field name="VAR" id="scalePattern">scalePattern</field></block></value><value name="ScalePatternV"><block type="variables_get" id="getScalePattern2"><field name="VAR" id="scalePattern">scalePattern</field></block></value><value name="OffsetFromBorderU"><block type="math_number" id="offsetU2"><field name="NUM">0</field></block></value><value name="OffsetFromBorderV"><block type="math_number" id="offsetV2"><field name="NUM">0</field></block></value><value name="ExtendUUp"><block type="logic_boolean" id="extendUUpFalse2"><field name="BOOL">FALSE</field></block></value><value name="ExtendUBottom"><block type="logic_boolean" id="extendUBottomFalse2"><field name="BOOL">FALSE</field></block></value><value name="ExtendVUp"><block type="logic_boolean" id="extendVUpFalse2"><field name="BOOL">FALSE</field></block></value><value name="ExtendVBottom"><block type="logic_boolean" id="extendVBottomFalse2"><field name="BOOL">FALSE</field></block></value></block></value></block></value><next><block type="variables_set" id="setReversedWires"><field name="VAR" id="reversedWires">reversedWires</field><value name="VALUE"><block type="lists_create_with" id="emptyReversedWires"><mutation items="0"></mutation></block></value><next><block type="controls_for" id="forLoopReverse"><field name="VAR" id="i">i</field><value name="FROM"><block type="math_number" id="forStart"><field name="NUM">1</field></block></value><value name="TO"><block type="lists_length" id="hexWires2Length"><value name="VALUE"><block type="variables_get" id="getHexWires2Length"><field name="VAR" id="hexWires2">hexWires2</field></block></value></block></value><value name="BY"><block type="math_number" id="forStep"><field name="NUM">1</field></block></value><statement name="DO"><block type="lists_setIndex" id="addReversedWire"><mutation at="false"></mutation><field name="MODE">INSERT</field><field name="WHERE">LAST</field><value name="LIST"><block type="variables_get" id="getReversedWiresList"><field name="VAR" id="reversedWires">reversedWires</field></block></value><value name="TO"><block type="base_time_await_return" id="awaitReversedWire"><value name="Promise"><block type="bitbybit.occt.shapes.wire.reversedWire" id="reverseWire"><value name="Shape"><block type="lists_getIndex" id="getHexWire2"><mutation statement="false" at="true"></mutation><field name="MODE">GET</field><field name="WHERE">FROM_START</field><value name="VALUE"><block type="variables_get" id="getHexWires2ForReverse"><field name="VAR" id="hexWires2">hexWires2</field></block></value><value name="AT"><block type="variables_get" id="getIndex"><field name="VAR" id="i">i</field></block></value></block></value></block></value></block></value></block></statement><next><block type="variables_set" id="setFrames"><field name="VAR" id="frames">frames</field><value name="VALUE"><block type="lists_create_with" id="emptyFrames"><mutation items="0"></mutation></block></value><next><block type="controls_for" id="forLoopFrames"><field name="VAR" id="i">i</field><value name="FROM"><block type="math_number" id="forStartFrames"><field name="NUM">1</field></block></value><value name="TO"><block type="lists_length" id="hexWires1Length"><value name="VALUE"><block type="variables_get" id="getHexWires1Length"><field name="VAR" id="hexWires1">hexWires1</field></block></value></block></value><value name="BY"><block type="math_number" id="forStepFrames"><field name="NUM">1</field></block></value><statement name="DO"><block type="lists_setIndex" id="addFrame"><mutation at="false"></mutation><field name="MODE">INSERT</field><field name="WHERE">LAST</field><value name="LIST"><block type="variables_get" id="getFramesList"><field name="VAR" id="frames">frames</field></block></value><value name="TO"><block type="base_time_await_return" id="awaitFrame"><value name="Promise"><block type="bitbybit.occt.shapes.face.createFaceFromWires" id="createFrame"><value name="Shapes"><block type="lists_create_with" id="frameWires"><mutation items="2"></mutation><value name="ADD0"><block type="lists_getIndex" id="getHexWire1"><mutation statement="false" at="true"></mutation><field name="MODE">GET</field><field name="WHERE">FROM_START</field><value name="VALUE"><block type="variables_get" id="getHexWires1ForFrame"><field name="VAR" id="hexWires1">hexWires1</field></block></value><value name="AT"><block type="variables_get" id="getIndexFrame"><field name="VAR" id="i">i</field></block></value></block></value><value name="ADD1"><block type="lists_getIndex" id="getReversedWire"><mutation statement="false" at="true"></mutation><field name="MODE">GET</field><field name="WHERE">FROM_START</field><value name="VALUE"><block type="variables_get" id="getReversedWiresForFrame"><field name="VAR" id="reversedWires">reversedWires</field></block></value><value name="AT"><block type="variables_get" id="getIndexFrameReversed"><field name="VAR" id="i">i</field></block></value></block></value></block></value><value name="Planar"><block type="logic_boolean" id="planarFalse"><field name="BOOL">FALSE</field></block></value></block></value></block></value></block></statement><next><block type="variables_set" id="setFramesCompound"><field name="VAR" id="framesCompound">firstFramesCompound</field><value name="VALUE"><block type="base_time_await_return" id="awaitCompound"><value name="Promise"><block type="bitbybit.occt.shapes.compound.makeCompound" id="makeCompound"><value name="Shapes"><block type="bitbybit.lists.getByPattern" id="o^dBq}wZKWX:jX;U|]EM"><value name="List"><block type="variables_get" id="getFrames"><field name="VAR" id="frames">frames</field></block></value><value name="Pattern"><block type="bitbybit.json.parse" id="fME_5AFkk$BKCIdifO!q"><value name="Text"><block type="text" id="[pnz[WR`-:UbL-?C*p?c"><field name="TEXT">[true, true, false]</field></block></value></block></value></block></value></block></value></block></value><next><block type="variables_set" id="@[2a#cJ6|`.ixSm}agpw"><field name="VAR" id="F@k=@{Ucm4;)F4yhAd0o">secondFramesCompound</field><value name="VALUE"><block type="base_time_await_return" id="qiC4P]d_!-xZs09^v7=%"><value name="Promise"><block type="bitbybit.occt.shapes.compound.makeCompound" id="om3]!BsB*hqTzFN^`(h@"><value name="Shapes"><block type="bitbybit.lists.getByPattern" id="N[{CbC)oC`ri;qQ5U%O."><value name="List"><block type="variables_get" id="|=wB*]?d*q)QnG9MAE=g"><field name="VAR" id="frames">frames</field></block></value><value name="Pattern"><block type="bitbybit.json.parse" id="u2]x-wd$#.j,$Cm|7[rj"><value name="Text"><block type="text" id="RLLo9PNs1wo0G(?_(pC("><field name="TEXT">[false,false,true]</field></block></value></block></value></block></value></block></value></block></value><next><block type="variables_set" id="setBlueMaterial"><field name="VAR" id="blueMaterial">material1</field><value name="VALUE"><block type="bitbybit.babylon.material.pbrMetallicRoughness.create" id="createBlueMaterial"><value name="Name"><block type="text" id="materialName"><field name="TEXT">First</field></block></value><value name="BaseColor"><block type="text" id="baseColor"><field name="TEXT">#9155ff</field></block></value><value name="EmissiveColor"><block type="text" id="emissiveColor"><field name="TEXT">#000000</field></block></value><value name="Metallic"><block type="math_number" id="metallic"><field name="NUM">0.15</field></block></value><value name="Roughness"><block type="math_number" id="roughness"><field name="NUM">0.9</field></block></value><value name="Alpha"><block type="math_number" id="alpha"><field name="NUM">1</field></block></value><value name="BackFaceCulling"><block type="logic_boolean" id="backFaceCulling"><field name="BOOL">FALSE</field></block></value><value name="ZOffset"><block type="math_number" id="zOffset"><field name="NUM">3</field></block></value></block></value><next><block type="variables_set" id="sXZf)^8uv(cy=Y:~P2uv"><field name="VAR" id="K0A$dz_a?K_Sr(;(R^mV">material2</field><value name="VALUE"><block type="bitbybit.babylon.material.pbrMetallicRoughness.create" id="P*y.SbyVr|3B(*Pj{,OQ"><value name="Name"><block type="text" id="*{z4o|I=0~f8Yr=t$k;V"><field name="TEXT">Second</field></block></value><value name="BaseColor"><block type="text" id="*Eis9;8hX8FV(liIFC9D"><field name="TEXT">#000000</field></block></value><value name="EmissiveColor"><block type="text" id="[2*D3BzaEQAYd%r7P[tG"><field name="TEXT">#000000</field></block></value><value name="Metallic"><block type="math_number" id="G+Fn=.fREWU?A8A:h$9j"><field name="NUM">0.9</field></block></value><value name="Roughness"><block type="math_number" id="D5o)?2NB2Yb-4;z/oV!2"><field name="NUM">0.15</field></block></value><value name="Alpha"><block type="math_number" id="9eYwgefcdd1duwIUKP@v"><field name="NUM">1</field></block></value><value name="BackFaceCulling"><block type="logic_boolean" id="/.Uy4D($ikvs6XD0@kGC"><field name="BOOL">FALSE</field></block></value><value name="ZOffset"><block type="math_number" id="EKDi8bT?7~mbBD?RiT-:"><field name="NUM">3</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="drawCompound"><value name="Entity"><block type="variables_get" id="getFramesCompound"><field name="VAR" id="framesCompound">firstFramesCompound</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeMaterial" id="drawOptions"><value name="Precision"><block type="math_number" id="precision"><field name="NUM">0.01</field></block></value><value name="FaceMaterial"><block type="variables_get" id="getBlueMaterial"><field name="VAR" id="blueMaterial">material1</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="drawEdges"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="text" id="edgeColour"><field name="TEXT">#000000</field></block></value><value name="EdgeWidth"><block type="math_number" id="edgeWidth"><field name="NUM">10</field></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn" id="fi4OvB[IEx#8WL-N5hKC"><value name="Entity"><block type="variables_get" id="Xrqi)9G4w~-`/%sMLF-="><field name="VAR" id="F@k=@{Ucm4;)F4yhAd0o">secondFramesCompound</field></block></value><value name="Options"><block type="bitbybit.draw.optionsOcctShapeMaterial" id="/2tqCet4bO2Tt=FNt?0r"><value name="Precision"><block type="math_number" id="RHrXc0`w*7^87poF3,)1"><field name="NUM">0.01</field></block></value><value name="FaceMaterial"><block type="variables_get" id="dRmNMTOIfey-#ofXED!#"><field name="VAR" id="K0A$dz_a?K_Sr(;(R^mV">material2</field></block></value><value name="DrawEdges"><block type="logic_boolean" id="b]v$:0yOB#Tij_p$5!@B"><field name="BOOL">TRUE</field></block></value><value name="EdgeColour"><block type="text" id="T~]AXDjE0ynT0Of`Y/;A"><field name="TEXT">#000000</field></block></value><value name="EdgeWidth"><block type="math_number" id="4!_h%QQ=}9v*R+Irr-Bx"><field name="NUM">10</field></block></value></block></value></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block></next></block><block type="bitbybit.babylon.scene.drawDirectionalLightNoReturn" id=")t{2E%ehY-a74dKbvxfs" x="874" y="-483"><value name="Direction"><block type="bitbybit.vector.vectorXYZ" id="_52a;T%w/``P=KII*EH/"><value name="X"><block type="math_number" id="v(?K(]wiM_/GN!Ti|3}]"><field name="NUM">-100</field></block></value><value name="Y"><block type="math_number" id="Hp,OY|-;oAjlSLrhT20I"><field name="NUM">-100</field></block></value><value name="Z"><block type="math_number" id="xJz4?i8v}r|h$L3i#YB;"><field name="NUM">-100</field></block></value></block></value><value name="Intensity"><block type="math_number" id="s/aURW]QPBoex`JfOT(|"><field name="NUM">3</field></block></value><value name="Diffuse"><block type="colour_picker" id="_Da^3#JHb^B7v4AVU~2/"><field name="COLOUR">#ffffff</field></block></value><value name="Specular"><block type="colour_picker" id="IHDxUg{xB)EyExW(rg:b"><field name="COLOUR">#ffffff</field></block></value><value name="ShadowGeneratorMapSize"><block type="math_number" id="GQo02o8Toa1jhA}g#b#G"><field name="NUM">1024</field></block></value><value name="EnableShadows"><block type="logic_boolean" id="7U4nfPF~Fdt$#Gp_}$(["><field name="BOOL">TRUE</field></block></value><value name="ShadowDarkness"><block type="math_number" id="ZV]}u?}z)f?etv-!1E4h"><field name="NUM">0</field></block></value><value name="ShadowUsePercentageCloserFiltering"><block type="logic_boolean" id="forBF^nXv~iD7LcwxIA^"><field name="BOOL">TRUE</field></block></value><value name="ShadowContactHardeningLightSizeUVRatio"><block type="math_number" id="(#)^0`m_Kn,LIKNC`n;f"><field name="NUM">0.2</field></block></value><value name="ShadowBias"><block type="math_number" id="o,ov|}f5!8@0%qzf!GmY"><field name="NUM">0.0001</field></block></value><value name="ShadowNormalBias"><block type="math_number" id=":ZEG8r`q^~X?,tqeh=3/"><field name="NUM">0.002</field></block></value><value name="ShadowMaxZ"><block type="math_number" id="_G4U0t%vv%lz.//i3Rc@"><field name="NUM">1000</field></block></value><value name="ShadowMinZ"><block type="math_number" id="O|X%sd@@T~W.6I,ItiE^"><field name="NUM">0</field></block></value><next><block type="bitbybit.babylon.scene.enableSkybox" id="l}|NVC-ON-/~Gb]ec3F/"><value name="Skybox"><block type="bitbybit.babylon.enums.skyboxEnum" id="U`XepMFg4oq`X]!0!|0O"><field name="bitbybit.babylon.enums.skyboxEnum">'default'</field></block></value><value name="Size"><block type="math_number" id="?oa^d#~nrUz*y2V^.MkO"><field name="NUM">1000</field></block></value><value name="Blur"><block type="math_number" id="`Mm`gJ~G^pTq.tbXhcAo"><field name="NUM">0.1</field></block></value><value name="EnvironmentIntensity"><block type="math_number" id="#l62l:!.O=/;2nY*1iSo"><field name="NUM">0.7</field></block></value><value name="HideSkybox"><block type="logic_boolean" id="TsMQ!ww_Ro0PkI+j]Qz2"><field name="BOOL">TRUE</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera" id=".L6.dCkP-N0`L/VCwqe;"><value name="Position"><block type="bitbybit.point.pointXYZ" id="H(;kMCcQ22LiynbQYf[b"><value name="X"><block type="math_number" id="+Ll{cJzA*sSx5hU{%_Ht"><field name="NUM">44</field></block></value><value name="Y"><block type="math_number" id="jI~ERDleo:lfcD;=/jlB"><field name="NUM">22</field></block></value><value name="Z"><block type="math_number" id="*nY+kH-~?8nc[A4G%*LY"><field name="NUM">44</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ" id="1T)60_;jmgzhUow0[V4@"><value name="X"><block type="math_number" id="lW[8|HW!=d2o=BI/%M*e"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number" id="65S38jQKfr^!|s1Ni0|f"><field name="NUM">15</field></block></value><value name="Z"><block type="math_number" id="@S|Q5Cg0j;EjKPZ5pY}^"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number" id="G*FtWf(o7!,~kZS]E.g,"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number" id="07+Y%e{KQ=tw+#n/7f_~"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number" id="~N{Fw5fx9I6Uf)1.4Juw"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number" id="FxHJ|Enou0t3b*d!gp]N"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number" id="]oe3kPnJS.#gzpFb0:BM"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number" id="09#1JbTYQ9H6Vu=dq/6a"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number" id="k_9QD/%f1uVw,q.kVN[@"><field name="NUM">3</field></block></value><next><block type="bitbybit.draw.drawGridMeshNoReturn" id="}/Ow8[Vycqu?4Xo6zOVV"><value name="Width"><block type="math_number" id="$olYgi6LTb.ZJ9xU]4!^"><field name="NUM">400</field></block></value><value name="Height"><block type="math_number" id="I3Ma?1+FI*qk*edUnE[@"><field name="NUM">400</field></block></value><value name="Subdivisions"><block type="math_number" id="*K3sdH(!1K:;Mpy19PL?"><field name="NUM">10</field></block></value><value name="MajorUnitFrequency"><block type="math_number" id="]5@*}E0/CsOz-`C/U;$#"><field name="NUM">10</field></block></value><value name="MinorUnitVisibility"><block type="math_number" id="X?-I(pav^Y40#I-WQ/rR"><field name="NUM">0.45</field></block></value><value name="GridRatio"><block type="math_number" id=":G,mZf(C5xBBkR57QYz`"><field name="NUM">0.5</field></block></value><value name="Opacity"><block type="math_number" id="~Hy!.5.1UD[0r`aCn,t6"><field name="NUM">0.5</field></block></value><value name="BackFaceCulling"><block type="logic_boolean" id="yKmYXJ(U@LiyOlx0zKNv"><field name="BOOL">FALSE</field></block></value><value name="MainColor"><block type="colour_picker" id="5Q0G95X.J8@=eFpQA|Tf"><field name="COLOUR">#ffffff</field></block></value><value name="SecondaryColor"><block type="colour_picker" id="}6.^G,#FJ-T82^eKqyLL"><field name="COLOUR">#ffffff</field></block></value></block></next></block></next></block></next></block><block type="bitbybit.babylon.scene.twoColorLinearGradient" id="wvLupSU1tH:p-i+n~(*K" x="538" y="116"><value name="ColorFrom"><block type="text" id="kMPMMTa$JXXZ`c|{%u!U"><field name="TEXT">#050506</field></block></value><value name="ColorTo"><block type="text" id="4!M^zM_pIu(3$:^nMt2B"><field name="TEXT">#627a9d</field></block></value><value name="Direction"><block type="bitbybit.babylon.enums.gradientDirectionEnum" id="ev:nf-vFNB}wvaJY(4:-"><field name="bitbybit.babylon.enums.gradientDirectionEnum">'to top'</field></block></value><value name="StopFrom"><block type="math_number" id="Xpwe0EWm.*D#-#!{EfR0"><field name="NUM">0</field></block></value><value name="StopTo"><block type="math_number" id="-EVn+PW$q9ud,$xo@^$g"><field name="NUM">100</field></block></value></block></xml>
// Import required DTOs for wire creation, lofting, face operations, and compounds
const { InterpolationDto, LoftDto, ShapeIndexDto, FaceSubdivideToHexagonWiresDto, FaceFromWiresDto, CompoundShapesDto } = Bit.Inputs.OCCT;
const { DrawOcctShapeOptions, SceneDrawGridMeshDto } = Bit.Inputs.Draw;
const { PBRMetallicRoughnessDto } = Bit.Inputs.BabylonMaterial;
const { CameraConfigurationDto, DirectionalLightDto, SceneTwoColorLinearGradientDto, SkyboxDto } = Bit.Inputs.BabylonScene;
const { skyboxEnum, gradientDirectionEnum } = Bit.Inputs.Base;
// Import type definitions for type safety
type Point3 = Bit.Inputs.Base.Point3;
type Vector3 = Bit.Inputs.Base.Vector3;
type TopoDSWirePointer = Bit.Inputs.OCCT.TopoDSWirePointer;
type TopoDSFacePointer = Bit.Inputs.OCCT.TopoDSFacePointer;
type TopoDSCompoundPointer = Bit.Inputs.OCCT.TopoDSCompoundPointer;
// Get access to OCCT modules
const { wire, face, compound } = bitbybit.occt.shapes;
const { operations } = bitbybit.occt;
const { material } = bitbybit.babylon;
const { scene } = bitbybit.babylon;
// Define the main function to create complex face compound
const start = async () => {
// Define point sets for three different wire levels
const bottomPoints: Point3[] = [
[-30, 0, -20],
[-10, 0, 0],
[0, 0, 10],
[10, 0, 0],
[30, 0, -20]
];
const middlePoints: Point3[] = [
[-20, 20, -10],
[-5, 20, 15],
[0, 20, 20],
[5, 20, 15],
[20, 20, -10]
];
const topPoints: Point3[] = [
[-15, 30, 0],
[-5, 30, 5],
[0, 30, 10],
[5, 30, 5],
[15, 30, 0]
];
// Create wires by interpolating points
const bottomWireOptions = new InterpolationDto();
bottomWireOptions.points = bottomPoints;
bottomWireOptions.periodic = false;
bottomWireOptions.tolerance = 0.1;
const bottomWire = await wire.interpolatePoints(bottomWireOptions);
const middleWireOptions = new InterpolationDto();
middleWireOptions.points = middlePoints;
middleWireOptions.periodic = false;
middleWireOptions.tolerance = 0.1;
const middleWire = await wire.interpolatePoints(middleWireOptions);
const topWireOptions = new InterpolationDto();
topWireOptions.points = topPoints;
topWireOptions.periodic = false;
topWireOptions.tolerance = 0.1;
const topWire = await wire.interpolatePoints(topWireOptions);
// Create list of wires for lofting
const wiresList = [bottomWire, middleWire, topWire];
// Loft the wires to create a surface
const loftOptions = new LoftDto<TopoDSWirePointer>();
loftOptions.shapes = wiresList;
loftOptions.makeSolid = false;
const loftedSurface = await operations.loft(loftOptions);
// Get the face from the lofted surface
const getFaceOptions = new ShapeIndexDto<TopoDSFacePointer>();
getFaceOptions.shape = loftedSurface;
getFaceOptions.index = 0;
const mainFace = await face.getFace(getFaceOptions);
// Subdivision parameters
const nrHexagonsU = 28;
const nrHexagonsV = 10;
const scalePattern = [0.7];
// Create first hexagon subdivision (regular pattern)
const hexSubdivision1Options = new FaceSubdivideToHexagonWiresDto<TopoDSFacePointer>();
hexSubdivision1Options.shape = mainFace;
hexSubdivision1Options.nrHexagonsU = nrHexagonsU;
hexSubdivision1Options.nrHexagonsV = nrHexagonsV;
const hexWires1 = await face.subdivideToHexagonWires(hexSubdivision1Options);
// Create second hexagon subdivision (scaled pattern)
const hexSubdivision2Options = new FaceSubdivideToHexagonWiresDto<TopoDSFacePointer>();
hexSubdivision2Options.shape = mainFace;
hexSubdivision2Options.nrHexagonsU = nrHexagonsU;
hexSubdivision2Options.nrHexagonsV = nrHexagonsV;
hexSubdivision2Options.scalePatternU = scalePattern;
hexSubdivision2Options.scalePatternV = scalePattern;
const hexWires2 = await face.subdivideToHexagonWires(hexSubdivision2Options);
// Reverse the wires from the second subdivision using for loop
const reversedWiresPromises: Promise<TopoDSWirePointer>[] = [];
for (const hexWire of hexWires2) {
const reversedWire = wire.reversedWire({ shape: hexWire });
reversedWiresPromises.push(reversedWire);
}
const reversedWires = await Promise.all(reversedWiresPromises);
// Combine both wire sets - equivalent to flip lists operation in Rete
const frameWiresGrouped = hexWires1.map((h, i) => [h, reversedWires[i]]);
// Create frames
const framePromises = frameWiresGrouped.map(f => {
const faceFromWires2Options = new FaceFromWiresDto<TopoDSWirePointer>();
faceFromWires2Options.shapes = f;
faceFromWires2Options.planar = false;
return face.createFaceFromWires(faceFromWires2Options);
});
const frames = await Promise.all(framePromises);
const firstFrames = await bitbybit.lists.getByPattern({
list: frames,
pattern: [true, true, false]
});
const secondFrames = await bitbybit.lists.getByPattern({
list: frames,
pattern: [false, false, true]
})
// Create first compound from the first pattern of hexagon faces
const compoundOptions = new CompoundShapesDto<TopoDSFacePointer>();
compoundOptions.shapes = firstFrames;
const firstCompound = await compound.makeCompound(compoundOptions);
// Create second compound from the first pattern of hexagon faces
compoundOptions.shapes = secondFrames;
const secondCompound = await compound.makeCompound(compoundOptions);
// Create materials for rendering
const firstMaterial = new PBRMetallicRoughnessDto();
firstMaterial.name = "Blue Material";
firstMaterial.baseColor = "#9155ff";
firstMaterial.metallic = 0.1;
firstMaterial.roughness = 0.9;
firstMaterial.backFaceCulling = false;
firstMaterial.zOffset = 3;
const blueMatResult = material.pbrMetallicRoughness.create(firstMaterial);
// Create drawing options for the first frames
const firstDrawOptions = new DrawOcctShapeOptions();
firstDrawOptions.drawEdges = true;
firstDrawOptions.edgeColour = "#000000";
firstDrawOptions.edgeWidth = 10;
firstDrawOptions.faceMaterial = blueMatResult;
bitbybit.draw.drawAnyAsync({
entity: firstCompound,
options: firstDrawOptions
});
// Create materials for rendering
const secondMaterial = new PBRMetallicRoughnessDto();
secondMaterial.name = "Black Material";
secondMaterial.baseColor = "#000000";
secondMaterial.metallic = 0.9;
secondMaterial.roughness = 0.23;
secondMaterial.backFaceCulling = false;
secondMaterial.zOffset = 3;
const secondMatResult = material.pbrMetallicRoughness.create(secondMaterial);
// Create drawing options for the first frames
const secondDrawOptions = new DrawOcctShapeOptions();
secondDrawOptions.drawEdges = true;
secondDrawOptions.edgeColour = "#000000";
secondDrawOptions.edgeWidth = 10;
secondDrawOptions.faceMaterial = secondMatResult;
bitbybit.draw.drawAnyAsync({
entity: secondCompound,
options: secondDrawOptions
});
// Set up scene lighting and camera
const skyboxOptions = new SkyboxDto();
skyboxOptions.skybox = skyboxEnum.city;
skyboxOptions.hideSkybox = true;
scene.enableSkybox(skyboxOptions);
const dirLightOptions = new DirectionalLightDto();
dirLightOptions.intensity = 3;
scene.drawDirectionalLight(dirLightOptions);
const gradientBackgroundOptions = new SceneTwoColorLinearGradientDto();
gradientBackgroundOptions.colorFrom = "#050506";
gradientBackgroundOptions.colorTo = "#627a9d";
gradientBackgroundOptions.direction = gradientDirectionEnum.toTop;
scene.twoColorLinearGradient(gradientBackgroundOptions);
const cameraConfigurationOptions = new CameraConfigurationDto();
cameraConfigurationOptions.position = [44, 30, 44];
cameraConfigurationOptions.lookAt = [0, 15, 0];
scene.adjustActiveArcRotateCamera(cameraConfigurationOptions);
const gridOptions = new SceneDrawGridMeshDto();
bitbybit.draw.drawGridMesh(gridOptions);
}
// Execute the function
start();
Understanding the Workflow: Step-by-Step Breakdown
Let's examine how this complex example demonstrates advanced compound usage by breaking down the key phases:
Phase 1: Surface Creation Through Lofting
The workflow begins by creating a complex curved surface that will serve as the foundation for our hexagonal pattern. This involves several steps:
-
Point Definition: Three distinct sets of 3D points define the profile curves at different heights - bottom, middle, and top levels with varying shapes and positions.
-
Wire Interpolation: Each point set is converted into smooth interpolated wires using
interpolatePoints(), creating the skeletal framework for the surface. -
Surface Lofting: The three wires are lofted together using
operations.loft()to create a complex curved surface that transitions smoothly between the different profile shapes.
This foundational surface provides the 3D canvas on which our hexagonal pattern will be projected.
Phase 2: Dual Pattern Generation
The core innovation of this example lies in creating two complementary hexagonal patterns on the same surface:
-
Primary Pattern: The surface is subdivided using
face.subdivideToHexagonWires()with standard parameters, creating an array of hexagonal wire outlines. -
Secondary Pattern: A second subdivision is created using the same parameters but with added scaling factors (
scalePatternUandscalePatternVset to 0.7), producing smaller hexagons that nest within the primary pattern. -
Wire Direction Management: The wires from the secondary pattern are reversed using
wire.reversedWire()to ensure proper face creation when combined with the primary pattern wires.
Phase 3: Frame Construction and Strategic Grouping
The two wire sets are combined to create individual hexagonal frames:
-
Frame Assembly: Each hexagon frame is created by pairing a wire from the primary pattern with the corresponding reversed wire from the secondary pattern, then using
face.createFaceFromWires()to create the actual geometric face. -
Pattern-Based Filtering: Using
bitbybit.lists.getByPattern(), the frames are separated into logical groups. The patterns[true, true, false]and[false, false, true]create alternating groupings that distribute the frames across different visual layers. -
Compound Creation: Each filtered group is consolidated into a separate compound using
compound.makeCompound(), transforming hundreds of individual faces into just two cohesive entities.
Phase 4: Optimized Rendering with Material Differentiation
The final phase demonstrates the rendering advantages of compounds:
-
Material Assignment: Different materials are created for each compound group - a purple metallic material for the first compound and a black metallic material for the second.
-
Single Draw Calls: Instead of rendering each hexagonal frame individually (which could be hundreds of draw calls), only two
bitbybit.draw.drawAnyAsync()calls are made - one for each compound. -
Unified Processing: The graphics pipeline processes each compound as a single mesh, dramatically reducing computational overhead while maintaining the visual complexity of the pattern.
Performance Impact Analysis
This example demonstrates several critical performance optimizations that compounds enable:
GPU Efficiency: Without compounds, a pattern with 280 hexagonal frames would require 280 separate GPU draw calls. With compounds, this reduces to just 2 draw calls - a 99% reduction in rendering overhead.
Memory Consolidation: Individual geometries each require separate memory allocation and management. Compounds consolidate this into unified memory blocks, reducing fragmentation and improving cache efficiency.
Transformation Performance: If you needed to rotate or translate this entire pattern, compounds allow you to transform both groups with just two operations instead of potentially hundreds of individual transformations.
Material Management: Rather than managing materials for hundreds of individual objects, you only need to manage materials for the compound groups, simplifying state changes and reducing GPU state switching overhead.
Best Practices for Complex Patterns
This example illustrates several important patterns for effective compound usage:
-
Logical Grouping: Group geometries that share similar properties (materials, transformation behavior, visibility states) into the same compound.
-
Pattern-Based Organization: Use systematic filtering (like the pattern-based selection shown) to create logical hierarchies rather than arbitrary groupings.
-
Strategic Timing: Create compounds after all individual geometry generation is complete but before rendering operations begin.
-
Balance Complexity: While compounds improve performance, extremely large compounds can become unwieldy. Consider breaking very large patterns into multiple logical compound groups.
-
Material Strategy: Design your material workflow around compound groupings rather than individual geometries to maximize the rendering efficiency gains.
This advanced example demonstrates how compounds scale from simple grouping mechanisms to sophisticated performance optimization tools in complex parametric design workflows.



