Three.js 3DM Loader fails to load BREPs

Hi there,

I use the rhino3dm.js library to export geometry to Rhino as NurbsCurves, BREPs, extrusions, …

When I want to re-import the File again with the Three.js 3DM Loader I get this error:

Does someone know what I can do either in the loading or in the export process to make it work?

My export looks like this:

export() {
    this.convert()
    let output = this.doc.toByteArray()
    const date = new Date().getFullYear() + '-' + (new Date().getMonth() + 1) + '-' + new Date().getDate()
    const blob = new Blob([output], { type: 'application/octect-stream' });
    const projectName = this.logic.projectSettings.project.name
    const sketchName = this.logic.projectSettings.sketch.name
    this.logic.emit('download', { blob, name: `${projectName}_${sketchName}_${date}.3dm` })
}

Where convert() calls methods like this:

polylineToRhinoOpenPolysurface(polyine: Polyline, unit: string) {
    const mesh = this.meshFromCurve(polyine)
    const rhinoMesh = this.rhino.Mesh.createFromThreejsJSON({ data: mesh.geometry })
    const brep = this.rhino.Brep.createFromMesh(rhinoMesh, false)
    if (unit === 'millimeter') brep.scale(1000)
    return brep
}
polylineToRhinoBrep(polyine: Polyline, extrusionHeight: number, unit: string) {
    const curvePoints = new this.rhino.Point3dList()
    polyine.pts.forEach(pt => curvePoints.add(pt[0], pt[1], pt[2]))
    const curve = this.rhino.NurbsCurve.create(false, 1, curvePoints)
    const brep = this.rhino.Extrusion.create(curve, extrusionHeight, true).toBrep(false)
    if (unit === 'millimeter') brep.scale(1000)
    return brep
}

The problem happens only on re-imported scenes.
Any help would be more than appreciated! :slight_smile:

Apparently, this mentioned from @fraguada is the problem

Is it possible to adapt the export so I don’t have to manually change to Render/Shaded Mode in Rhino?

Or setting options in the export forcing Rhino to open the document in one of these modes :sweat_smile:

Where are you exporting from? The only software that knows how to generate render meshes for extrusions, breps, and subD is Rhino. You’d have to open the file in Rhino to have it generate render meshes (or script the generation of render meshes from within Rhino).

Alternatively, we could bind the SetMesh method of these types to allow users to add their own render mesh to these geometries from outside of Rhino. (I’ll add this issue to our list).

I export it from a web app using the rhino3dm.js.

We want to include Rhino in our workflow, so import and export to Rhino
I just noticed that I have to open an exported Rhino file in Render or Shaded Mode (Wireframe is not enough) so that it is possible to import it with the Three.js 3DM Loader.

Don’t know if the mentioned approach would help with that

Right. Render meshes are only generated on breps in Rhino itself. What I can do is bind the SetMesh function for BrepFaces and for Extrusions in rhino3dm so that you can push your own meshes to those objects and save them in the 3dm. Does that sound like a solution for your process?

2 Likes

Yes, that would be very helpful!

1 Like

Hello. I’ve wrapped the SetMesh functionality for breps and extrusions. I’d appreciate if you could try it out by downloading the compiled version that can be found here (available for 15 days).

In theory, you should be able to do do the following:


let myRhinoMesh
// create your Rhino mesh

//object is an object from doc.objects()

//for extrusions:
const resultExtrusion = object.geometry().setMesh( myRhinoMesh, rhino.MeshType.Render ); //result is a bool

//for a brepface with index 0 in the brep
const resultBrepFace = object.geometry().faces().get(0).setMesh( myRhinoMesh, rhino.MeshType.Render ) //result is a bool

1 Like

Just tested this very simple example:

//...
const radius = 10
const geometry = new THREE.SphereGeometry( radius, 32, 32 )
const rhinoBrep = rhino.Brep.createFromSphere( new rhino.Sphere( [0,0,0], radius )
const rhinoMesh = rhino.Mesh.createFromThreejsJSON( { data: geometry } )
const result = rhinoBrep.faces().get(0).setMesh( rhinoMesh, rhino.MeshType.Render )

const brep_layer_index = doc.layers().addLayer( 'Breps', { r: 255, g: 255, b: 255, a: 255 } )
const oa_breps = new rhino.ObjectAttributes()
oa_breps.layerIndex = brep_layer_index

doc.objects().add( rhinoBrep, oa_breps )
//...

of course, this is pretty easy because a sphere brep has one face, so we can just put the sphere mesh in there. Stepping through the faces of a Brep and setting the mesh for the face would require quite some logic to get it right.

I was able to save this file and open it in the threejs editor and the meshes came through. I am working on a sample to demonstrate this, but the above code is the main part.

Thank you that’s awesome!
I downloaded the compiled version and will test as as soon as I can get to it.

1 Like

Works fine for extrusions (the boxes):


//...
const geometry = new THREE.BoxGeometry(5, 5, 5, 1, 1, 1)

const rhinoBox = new rhino.Box( new rhino.BoundingBox( [ -2.5, -2.5, -2.5 ], [ 2.5, 2.5, 2.5 ] ) )
const rhinoObject = rhino.Extrusion.createBoxExtrusion( rhinoBox, true )

const rhinoMesh = rhino.Mesh.createFromThreejsJSON( { data: geometry } )
const result = rhinoObject.setMesh( rhinoMesh, rhino.MeshType.Render)

const layer_index = doc.layers().addLayer( 'Breps', { r: 255, g: 255, b: 255, a: 255 } )
const oa = new rhino.ObjectAttributes()
oa.layerIndex = layer_index

doc.objects().add( rhinoObject, oa )

//...

1 Like

Sorry for the late reply
Simple examples worked for me as well!

But it might be more difficult for more complex BREPs - didn’t try this one yet

Will the setMesh() method be accessible in a new release of rhino3dm.js?

yes! We’ll do a beta release to npm soon.

1 Like

Hey guys, I’m having a similar issue with this. Basically I’m reading a rhino file using rhino3dm, then I create a new brep and save the file back. Later I open that saved file using the rhino3dmloader but I don’t see the mesh in the browser. Is there no better way of doing this mesh render update? I have also try to create a threejs geometry and use the setMesh method but for some reason it only shows the mesh in the same position. here is my code:

 const createSpaceDisk = (values, rhino) => {
    // Define cylinder dimensions
    const radius = 0.4;
    const height = 0.25;
    // Define the cylinder's base circle at the provided center
    const circle = new rhino.Circle(radius);
    circle.center = values.position;
    // Create the cylindrical surface (the height is along the Z-axis)
    const cylinder = new rhino.Cylinder(circle, height);
    // Create the Brep (boundary representation) from the cylinder
    const brep = rhino.Brep.createFromCylinder(cylinder, true, true); // Capped at both ends (top and bottom)
    // Create cylinder geometry
    return brep;
  };
const cylinderAttributes = setSpaceAttributes(newDoc, rhino, values);
newDoc.objects().add(newCylinder, cylinderAttributes);
uploadFile(newDoc);

Sorry I forgot to put the part with the three.js geometry:

const createSpaceDisk = (values, rhino) => {
    // Define cylinder dimensions
    const radius = 0.4;
    const height = 0.25;
    // Define the cylinder's base circle at the provided center
    const circle = new rhino.Circle(radius);
    circle.center = values.position;
    // Create the cylindrical surface (the height is along the Z-axis)
    const cylinder = new rhino.Cylinder(circle, height);
    // Create the Brep (boundary representation) from the cylinder
    const brep = rhino.Brep.createFromCylinder(cylinder, true, true); // Capped at both ends (top and bottom)
    // Create cylinder geometry
    const threeGeometry = new THREE.CylinderGeometry(
      radius,
      radius,
      height,
      32
    );
    const rhinoMesh = rhino.Mesh.createFromThreejsJSON({ data: threeGeometry });
    console.log(rhinoMesh);

    for (let i = 0; i < brep.faces().count; i++) {
      brep.faces().get(i).setMesh(rhinoMesh, rhino.MeshType.Render);
    }
    return brep;
  };

I’ll have to give this a try to see where the issue is. I’ve added an issue in the rhino3dm repo: Check roundtripping Brep.SetMesh() in ThreeJs · Issue #646 · mcneel/rhino3dm · GitHub

There no meshing included in rhino3dm. This is why the SetMesh method was exposed, so users could add their own meshes to breps.

The mesh you create in threejs should be in the same position as the brep. Please see this example that shows how I transform the threejs geometry: rhino-developer-samples/rhino3dm/js/SampleJSMakeBrep/script.js at 8 · mcneel/rhino-developer-samples · GitHub

Looking at the output of this example, I do see that my meshes are not transformed properly to the actual brep/extrusion location. I will tune this up.

Sample has been fixed. Now the threejs meshes are in the same position as the breps/extrusions.

1 Like

Awesome @fraguada Thanks for the quick fix!

1 Like