BREP, STL, OBJ and PLY
File formats split into two families, and the difference decides what you can do with a shape once it comes back.
An exact format keeps the geometry itself: this edge is a circle of radius 3. A mesh format keeps only flat triangles laid over the surface. Both look the same on screen until you come close, but only one can still be filleted, measured to the last digit or cut cleanly.
| Format | Keeps | Save | Read |
|---|---|---|---|
| BREP | Exact geometry and topology, in OCCT's own format | saveShapeBrep, saveShapeBrepBinary | loadBrep, loadBrepBinary |
| STEP, IGES | Exact geometry, for other CAD programs | See STEP and IGES | See STEP and IGES |
| STL | Triangles, as 3D printers and slicers read them | saveShapeStl | loadStl |
| OBJ | Triangles, as most 3D programs read them | saveShapeObj | assembly.manager.loadObjToDoc |
| PLY | Triangles with a normal per vertex | saveShapePly | - |
Each save function starts a browser download. Its ...AndReturn twin also hands the file's contents back to your script, and with tryDownload set to false it skips the download.
The same part both ways
This drum with rounded edges goes out and comes back twice. Through BREP, 2.6 KB of text, it returns as the same 5 faces. Through STL, 263 KB at a precision of 0.1, it returns as 828 flat triangles. Each triangle is its own face, drawn here with its edges:
- Rete
- Blockly
- TypeScript
{
"id": "rete-v2-json",
"nodes": {
"drum": {
"id": "drum",
"name": "bitbybit.occt.shapes.solid.createCylinder",
"customName": "cylinder",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 3,
"height": 5,
"center": [
0,
0,
0
],
"direction": [
0,
1,
0
],
"angle": 360,
"originOnCenter": false
},
"inputs": {},
"position": [
40,
40
]
},
"part": {
"id": "part",
"name": "bitbybit.occt.fillets.filletEdges",
"customName": "fillet edges",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"radius": 0.6
},
"inputs": {
"shape": {
"connections": [
{
"node": "drum",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
40
]
},
"brep": {
"id": "brep",
"name": "bitbybit.occt.io.saveShapeBrepAndReturn",
"customName": "save brep and return",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"fileName": "part.brep",
"tryDownload": false,
"withTriangulation": false
},
"inputs": {
"shape": {
"connections": [
{
"node": "part",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
40
]
},
"stl": {
"id": "stl",
"name": "bitbybit.occt.io.saveShapeStlAndReturn",
"customName": "save shape stl and return",
"async": true,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"fileName": "part.stl",
"precision": 0.1,
"adjustYtoZ": false,
"tryDownload": false,
"binary": false
},
"inputs": {
"shape": {
"connections": [
{
"node": "part",
"output": "result",
"data": {}
}
]
}
},
"position": [
880,
380
]
},
"exact": {
"id": "exact",
"name": "bitbybit.occt.io.loadBrep",
"customName": "load brep",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
}
},
"inputs": {
"brepData": {
"connections": [
{
"node": "brep",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
40
]
},
"facets": {
"id": "facets",
"name": "bitbybit.occt.io.loadStl",
"customName": "load stl",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"asFaces": true,
"adjustZtoY": false
},
"inputs": {
"stlData": {
"connections": [
{
"node": "stl",
"output": "result",
"data": {}
}
]
}
},
"position": [
1300,
280
]
},
"beside": {
"id": "beside",
"name": "bitbybit.occt.transforms.translate",
"customName": "translate",
"async": true,
"drawable": true,
"data": {
"genericNodeData": {
"hide": true,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"translation": [
8,
0,
0
]
},
"inputs": {
"shape": {
"connections": [
{
"node": "facets",
"output": "result",
"data": {}
}
]
}
},
"position": [
1720,
40
]
},
"steel": {
"id": "steel",
"name": "bitbybit.draw.optionsOcctShape",
"customName": "options occt shape",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"faceOpacity": 1,
"edgeOpacity": 1,
"edgeColour": "#5f6773",
"faceColour": "#ff0000",
"vertexColour": "#ff00ff",
"edgeWidth": 2,
"edgeWidthBySize": false,
"vertexSize": 0.03,
"drawEdges": true,
"drawFaces": true,
"drawVertices": false,
"precision": 0.01,
"angularDeflection": 0.5,
"relativeDeflection": false,
"precisionShare": 0,
"drawEdgeIndexes": false,
"edgeIndexHeight": 0.06,
"edgeIndexColour": "#ff00ff",
"drawFaceIndexes": false,
"faceIndexHeight": 0.06,
"faceIndexColour": "#0000ff",
"drawTwoSided": false,
"backFaceColour": "#0000ff",
"backFaceOpacity": 1,
"edgeArrowSize": 0,
"edgeArrowAngle": 15,
"keepMeshData": false,
"allowQualityDecrease": true,
"forceFaceDeflection": false,
"drawIsoCurves": false,
"isoCurvesU": 5,
"isoCurvesV": 5,
"isoCurvesColour": "#808080",
"surfaceAnalysis": "none",
"draftDirection": [
0,
1,
0
]
},
"inputs": {
"faceMaterial": {
"connections": [
{
"node": "steelMaterial",
"output": "result",
"data": {}
}
]
}
},
"position": [
460,
380
]
},
"steelMaterial": {
"id": "steelMaterial",
"name": "bitbybit.draw.createPBRMaterial",
"customName": "create pbr material",
"async": false,
"drawable": false,
"data": {
"genericNodeData": {
"hide": false,
"oneOnOne": false,
"flatten": 0,
"forceExecution": false
},
"name": "PBRMaterial",
"baseColor": "#eef0f2",
"metallic": 0.7,
"roughness": 0.3,
"alpha": 1,
"emissiveColor": "#000000",
"emissiveIntensity": 1,
"zOffset": 0,
"zOffsetUnits": 0,
"alphaMode": "opaque",
"alphaCutoff": 0.5,
"doubleSided": false,
"wireframe": false,
"unlit": false
},
"inputs": {},
"position": [
40,
472
]
},
"drawExact": {
"id": "drawExact",
"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": "exact",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "steel",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
40
]
},
"drawBeside": {
"id": "drawBeside",
"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": "beside",
"output": "result",
"data": {}
}
]
},
"options": {
"connections": [
{
"node": "steel",
"output": "result",
"data": {}
}
]
}
},
"position": [
2140,
334
]
},
"view": {
"id": "view",
"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": [
6,
13,
-19
],
"lookAt": [
4,
2,
0
],
"lowerBetaLimit": 1,
"upperBetaLimit": 179,
"angularSensibilityX": 1000,
"angularSensibilityY": 1000,
"maxZ": 1000,
"panningSensibility": 1000,
"wheelPrecision": 3
},
"inputs": {},
"position": [
2140,
628
]
}
},
"modules": {}
}
<xml xmlns="https://developers.google.com/blockly/xml"><variables><variable id="part">part</variable><variable id="steel">steel</variable></variables><block type="variables_set" x="40" y="200"><field name="VAR" id="part">part</field><value name="VALUE"><block type="bitbybit.occt.fillets.filletEdges"><value name="Shape"><block type="bitbybit.occt.shapes.solid.createCylinder"><value name="Radius"><block type="math_number"><field name="NUM">3</field></block></value><value name="Height"><block type="math_number"><field name="NUM">5</field></block></value><value name="Center"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Direction"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="Angle"><block type="math_number"><field name="NUM">360</field></block></value><value name="OriginOnCenter"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value><value name="Radius"><block type="math_number"><field name="NUM">0.6</field></block></value></block></value><next><block type="variables_set"><field name="VAR" id="steel">steel</field><value name="VALUE"><block type="bitbybit.draw.optionsOcctShape"><value name="FaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeColour"><block type="colour_picker"><field name="COLOUR">#5f6773</field></block></value><value name="FaceColour"><block type="colour_picker"><field name="COLOUR">#ff0000</field></block></value><value name="VertexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="FaceMaterial"><block type="bitbybit.draw.createPBRMaterial"><value name="Name"><block type="text"><field name="TEXT">PBRMaterial</field></block></value><value name="BaseColor"><block type="colour_picker"><field name="COLOUR">#eef0f2</field></block></value><value name="Metallic"><block type="math_number"><field name="NUM">0.7</field></block></value><value name="Roughness"><block type="math_number"><field name="NUM">0.3</field></block></value><value name="Alpha"><block type="math_number"><field name="NUM">1</field></block></value><value name="EmissiveColor"><block type="colour_picker"><field name="COLOUR">#000000</field></block></value><value name="EmissiveIntensity"><block type="math_number"><field name="NUM">1</field></block></value><value name="ZOffset"><block type="math_number"><field name="NUM">0</field></block></value><value name="ZOffsetUnits"><block type="math_number"><field name="NUM">0</field></block></value><value name="AlphaMode"><block type="bitbybit.draw.enums.alphaModeEnum"><field name="bitbybit.draw.enums.alphaModeEnum">'opaque'</field></block></value><value name="AlphaCutoff"><block type="math_number"><field name="NUM">0.5</field></block></value><value name="DoubleSided"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Wireframe"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Unlit"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value><value name="EdgeWidth"><block type="math_number"><field name="NUM">2</field></block></value><value name="EdgeWidthBySize"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="VertexSize"><block type="math_number"><field name="NUM">0.03</field></block></value><value name="DrawEdges"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawFaces"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="DrawVertices"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.01</field></block></value><value name="AngularDeflection"><block type="math_number"><field name="NUM">0.5</field></block></value><value name="RelativeDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="PrecisionShare"><block type="math_number"><field name="NUM">0</field></block></value><value name="DrawEdgeIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="EdgeIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="EdgeIndexColour"><block type="colour_picker"><field name="COLOUR">#ff00ff</field></block></value><value name="DrawFaceIndexes"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="FaceIndexHeight"><block type="math_number"><field name="NUM">0.06</field></block></value><value name="FaceIndexColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="DrawTwoSided"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="BackFaceColour"><block type="colour_picker"><field name="COLOUR">#0000ff</field></block></value><value name="BackFaceOpacity"><block type="math_number"><field name="NUM">1</field></block></value><value name="EdgeArrowSize"><block type="math_number"><field name="NUM">0</field></block></value><value name="EdgeArrowAngle"><block type="math_number"><field name="NUM">15</field></block></value><value name="KeepMeshData"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="AllowQualityDecrease"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="ForceFaceDeflection"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="DrawIsoCurves"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="IsoCurvesU"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesV"><block type="math_number"><field name="NUM">5</field></block></value><value name="IsoCurvesColour"><block type="colour_picker"><field name="COLOUR">#808080</field></block></value><value name="SurfaceAnalysis"><block type="bitbybit.occt.enums.surfaceAnalysisEnum"><field name="bitbybit.occt.enums.surfaceAnalysisEnum">'none'</field></block></value><value name="DraftDirection"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">0</field></block></value><value name="Y"><block type="math_number"><field name="NUM">1</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="bitbybit.occt.io.loadBrep"><value name="BrepData"><block type="bitbybit.occt.io.saveShapeBrepAndReturn"><value name="Shape"><block type="variables_get"><field name="VAR" id="part">part</field></block></value><value name="FileName"><block type="text"><field name="TEXT">part.brep</field></block></value><value name="TryDownload"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="WithTriangulation"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="steel">steel</field></block></value><next><block type="bitbybit.draw.drawAnyAsyncNoReturn"><value name="Entity"><block type="bitbybit.occt.transforms.translate"><value name="Shape"><block type="bitbybit.occt.io.loadStl"><value name="StlData"><block type="bitbybit.occt.io.saveShapeStlAndReturn"><value name="Shape"><block type="variables_get"><field name="VAR" id="part">part</field></block></value><value name="FileName"><block type="text"><field name="TEXT">part.stl</field></block></value><value name="Precision"><block type="math_number"><field name="NUM">0.1</field></block></value><value name="AdjustYtoZ"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="TryDownload"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value><value name="Binary"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value><value name="AsFaces"><block type="logic_boolean"><field name="BOOL">TRUE</field></block></value><value name="AdjustZtoY"><block type="logic_boolean"><field name="BOOL">FALSE</field></block></value></block></value><value name="Translation"><block type="bitbybit.vector.vectorXYZ"><value name="X"><block type="math_number"><field name="NUM">8</field></block></value><value name="Y"><block type="math_number"><field name="NUM">0</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value></block></value><value name="Options"><block type="variables_get"><field name="VAR" id="steel">steel</field></block></value><next><block type="bitbybit.babylon.scene.adjustActiveArcRotateCamera"><value name="Position"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">6</field></block></value><value name="Y"><block type="math_number"><field name="NUM">13</field></block></value><value name="Z"><block type="math_number"><field name="NUM">-19</field></block></value></block></value><value name="LookAt"><block type="bitbybit.point.pointXYZ"><value name="X"><block type="math_number"><field name="NUM">4</field></block></value><value name="Y"><block type="math_number"><field name="NUM">2</field></block></value><value name="Z"><block type="math_number"><field name="NUM">0</field></block></value></block></value><value name="LowerBetaLimit"><block type="math_number"><field name="NUM">1</field></block></value><value name="UpperBetaLimit"><block type="math_number"><field name="NUM">179</field></block></value><value name="AngularSensibilityX"><block type="math_number"><field name="NUM">1000</field></block></value><value name="AngularSensibilityY"><block type="math_number"><field name="NUM">1000</field></block></value><value name="MaxZ"><block type="math_number"><field name="NUM">1000</field></block></value><value name="PanningSensibility"><block type="math_number"><field name="NUM">1000</field></block></value><value name="WheelPrecision"><block type="math_number"><field name="NUM">3</field></block></value></block></next></block></next></block></next></block></next></block></xml>
const drum = await bitbybit.occt.shapes.solid.createCylinder({ radius: 3, height: 5, center: [0, 0, 0], direction: [0, 1, 0] });
const part = await bitbybit.occt.fillets.filletEdges({ shape: drum, radius: 0.6 });
const brep = await bitbybit.occt.io.saveShapeBrepAndReturn({ shape: part, fileName: "part.brep", tryDownload: false, withTriangulation: false });
const stl = await bitbybit.occt.io.saveShapeStlAndReturn({ shape: part, fileName: "part.stl", precision: 0.1, adjustYtoZ: false, tryDownload: false, binary: false });
const exact = await bitbybit.occt.io.loadBrep({ brepData: brep });
const facets = await bitbybit.occt.io.loadStl({ stlData: stl, asFaces: true, adjustZtoY: false });
const beside = await bitbybit.occt.transforms.translate({ shape: facets, translation: [8, 0, 0] });
const steel = new Bit.Inputs.Draw.DrawOcctShapeOptions();
steel.faceMaterial = bitbybit.draw.createPBRMaterial({ baseColor: "#eef0f2", metallic: 0.7, roughness: 0.3 });
steel.edgeColour = "#5f6773";
steel.drawTwoSided = false;
await bitbybit.draw.drawAnyAsync({ entity: exact, options: steel });
await bitbybit.draw.drawAnyAsync({ entity: beside, options: steel });
bitbybit.babylon.scene.adjustActiveArcRotateCamera({ position: [6, 13, -19], lookAt: [4, 2, 0] });
loadStl has two ways to read a file. With asFaces on, each triangle becomes a planar face, as here, which sewing can join into a shell. With it off, one face carries the whole mesh, which is light to draw but not for modelling.
precision sets how far a triangle may stray from the surface when a mesh is written. A smaller number gives a smoother surface and a larger file.



