I'm trying to export a Rhino.Geometry.Mesh
as an STL file with simple and straightforward approach.
I tried this code:
public static bool ExportMeshToStl(Mesh mesh, string fileName)
{
if (mesh == null || string.IsNullOrEmpty(fileName)) return false;
// Create a temporary layer to isolate the specific mesh
var tempLayer = new Layer { Name = "TempLayerForStlExport" };
int tempLayerIndex = RhinoDoc.ActiveDoc.Layers.Add(tempLayer);
if (tempLayerIndex < 0) return false;
// Add the mesh to the temporary layer
var attributes = new ObjectAttributes { LayerIndex = tempLayerIndex };
var meshId = RhinoDoc.ActiveDoc.Objects.AddMesh(mesh, attributes);
if (meshId == Guid.Empty)
{
RhinoDoc.ActiveDoc.Layers.Delete(tempLayerIndex, true);
return false;
}
// Use RhinoApp.RunScript to export the mesh on the temporary layer as an STL file
var script = $"_-Export \"{fileName}\" _Enter";
RhinoDoc.ActiveDoc.Layers.SetCurrentLayerIndex(tempLayerIndex, true);
bool result = RhinoApp.RunScript(script, false);
// Remove the mesh and the temporary layer from the current document
RhinoDoc.ActiveDoc.Objects.Delete(meshId, true);
RhinoDoc.ActiveDoc.Layers.Delete(tempLayerIndex, true);
return result;
}
But MeshLab cannot open the resulted mesh:
I couldn't find a straightforward & simple approach. Is there any?
I extract index and vertex buffers of a mesh by this method:
public static void GetMeshBuffers(Mesh mesh, out float[] vertexBuffer, out int[] indexBuffer)
{
// Convert quads to triangles
mesh.Faces.ConvertQuadsToTriangles();
// Get vertex buffer
Point3f[] vertices = mesh.Vertices.ToPoint3fArray();
vertexBuffer = new float[vertices.Length * 3];
for (int i = 0; i < vertices.Length; i++)
{
vertexBuffer[i * 3] = vertices[i].X;
vertexBuffer[i * 3 + 1] = vertices[i].Y;
vertexBuffer[i * 3 + 2] = vertices[i].Z;
}
// Get index buffer
MeshFace[] faces = mesh.Faces.ToArray();
indexBuffer = new int[faces.Length * 3];
for (int i = 0; i < faces.Length; i++)
{
MeshFace face = faces[i];
indexBuffer[i * 3] = face.A;
indexBuffer[i * 3 + 1] = face.B;
indexBuffer[i * 3 + 2] = face.C;
}
}
Then, I save the index and vertex buffers as STL by this method:
public static void SaveBuffersAsStl(float[] vertexBuffer, int[] indexBuffer, string fileName)
{
// Open the file for writing
using (FileStream fileStream = new FileStream(fileName, FileMode.Create))
{
// Write the STL header
byte[] header = new byte[80];
fileStream.Write(header, 0, header.Length);
// Write the number of triangles
int triangleCount = indexBuffer.Length / 3;
byte[] triangleCountBytes = BitConverter.GetBytes(triangleCount);
fileStream.Write(triangleCountBytes, 0, 4);
// Write the triangles
for (int i = 0; i < indexBuffer.Length; i += 3)
{
// Get vertices for the current triangle
float x1 = vertexBuffer[indexBuffer[i] * 3];
float y1 = vertexBuffer[indexBuffer[i] * 3 + 1];
float z1 = vertexBuffer[indexBuffer[i] * 3 + 2];
float x2 = vertexBuffer[indexBuffer[i + 1] * 3];
float y2 = vertexBuffer[indexBuffer[i + 1] * 3 + 1];
float z2 = vertexBuffer[indexBuffer[i + 1] * 3 + 2];
float x3 = vertexBuffer[indexBuffer[i + 2] * 3];
float y3 = vertexBuffer[indexBuffer[i + 2] * 3 + 1];
float z3 = vertexBuffer[indexBuffer[i + 2] * 3 + 2];
// Compute the normal vector of the triangle
float nx = (y2 - y1) * (z3 - z1) - (z2 - z1) * (y3 - y1);
float ny = (z2 - z1) * (x3 - x1) - (x2 - x1) * (z3 - z1);
float nz = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
float length = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz);
nx /= length;
ny /= length;
nz /= length;
// Write the normal vector
byte[] normal = new byte[12];
BitConverter.GetBytes(nx).CopyTo(normal, 0);
BitConverter.GetBytes(ny).CopyTo(normal, 4);
BitConverter.GetBytes(nz).CopyTo(normal, 8);
fileStream.Write(normal, 0, normal.Length);
// Write the vertices in counter-clockwise order
byte[] triangle = new byte[36];
BitConverter.GetBytes(x1).CopyTo(triangle, 12);
BitConverter.GetBytes(y1).CopyTo(triangle, 16);
BitConverter.GetBytes(z1).CopyTo(triangle, 20);
BitConverter.GetBytes(x3).CopyTo(triangle, 0);
BitConverter.GetBytes(y3).CopyTo(triangle, 4);
BitConverter.GetBytes(z3).CopyTo(triangle, 8);
BitConverter.GetBytes(x2).CopyTo(triangle, 24);
BitConverter.GetBytes(y2).CopyTo(triangle, 28);
BitConverter.GetBytes(z2).CopyTo(triangle, 32);
fileStream.Write(triangle, 0, triangle.Length);
// Write the triangle attribute (zero)
byte[] attribute = new byte[2];
fileStream.Write(attribute, 0, attribute.Length);
}
}
}
The above methods are called like this:
RhinoObject obj = GetSingleMesh();
// Check if object is valid.
Mesh mesh = obj.Geometry as Mesh;
// Check if mesh is valid.
// Extract vertex buffer and index buffer.
float[] vertexBuffer;
int[] indexBuffer;
GetMeshBuffers(mesh, out vertexBuffer, out indexBuffer);
SaveBuffersAsStl(vertexBuffer, indexBuffer, "mesh-out.stl");
Tests indicate that the above methods work just fine.