简体   繁体   中英

Export layers as obj from Rhino3d

The task

Export layers as obj files from Rhino.

The issue

When using Python scripting, I run an export command. Instead of exporting the model, a dialog is presented in the interface. If I click the export interface, it works fine. However it brings up the dialog box for every layer. I have many many layers though and I would like to automate the entire export process.

The end goal is to display the obj files in webGL via three.js.

I am new to Python and Rhino, but know PHP and JavaScript, so I understand the concepts well enough and have watched a few tutorials on Python so I can begin working on this script.

What I have tried

I am using Rhino, Atom/Python.

import scriptcontext
import rhinoscriptsyntax as rs
from Rhino.Geometry import Point3d

def layerNames(sort=False):
    rc = []
    for layer in scriptcontext.doc.Layers:
        if not layer.IsDeleted: rc.append(layer.FullPath)
    if sort: rc.sort()
    return rc


rs.EnableRedraw(False)

strPath = rs.DocumentPath()
strName = rs.DocumentName()

arrLayers = layerNames(False)
for layerName in arrLayers:
    objs = scriptcontext.doc.Objects.FindByLayer(layerName)
    rs.Command("_-Export "+layerName+".obj", False) 

Notes

I was thinking of using python native file saving (open("layername.json", "a"). The thought is to somehow get the mesh from the objects in each layer, convert that to three.js json and use that instead. But I don't know how to get a mesh from a layer. I have imported Rhino.Geometry to see if it was helpful. I don't know how to find a mesh to convert, or if I can somehow use the native export command in an automated fashion and just use obj files.

Here is the final script which exports dae, obj and stl. The settings in place are fairly aggressive polygon reductions. Adjust angle and density to change that.

I discovered that you need to set the density to zero before setting it to another value which solved a polygon count issue in the mesh conversion.

Also available on gist.

import os
import scriptcontext
import rhinoscriptsyntax as rs


print "//export run started/////////////"

# this function via mcneel/rhinoscriptsyntax
#https://github.com/mcneel/rhinoscriptsyntax/blob/master/Scripts/rhinoscript/layer.py
def layerNames(sort=False):
    rc = []
    for layer in scriptcontext.doc.Layers:
        if not layer.IsDeleted: rc.append(layer.FullPath)
    if sort: rc.sort()
    return rc

def GetDAESettings():
    e_str = ""
    return e_str

def GetOBJSettings():
    e_str = "_Geometry=_Mesh "
    e_str+= "_EndOfLine=CRLF "
    e_str+= "_ExportRhinoObjectNames=_ExportObjectsAsOBJGroups "
    e_str+= "_ExportMeshTextureCoordinates=_Yes "
    e_str+= "_ExportMeshVertexNormals=_No "
    e_str+= "_CreateNGons=_No "
    e_str+= "_ExportMaterialDefinitions=_No "
    e_str+= "_YUp=_No "
    e_str+= "_WrapLongLines=Yes "
    e_str+= "_VertexWelding=_Welded "
    e_str+= "_WritePrecision=4 "
    e_str+= "_Enter "

    e_str+= "_DetailedOptions "
    e_str+= "_JaggedSeams=_No "
    e_str+= "_PackTextures=_No "
    e_str+= "_Refine=_Yes "
    e_str+= "_SimplePlane=_No "

    e_str+= "_AdvancedOptions "
    e_str+= "_Angle=50 "
    e_str+= "_AspectRatio=0 "
    e_str+= "_Distance=0.0"
    e_str+= "_Density=0 "
    e_str+= "_Density=0.45 "
    e_str+= "_Grid=0 "
    e_str+= "_MaxEdgeLength=0 "
    e_str+= "_MinEdgeLength=0.0001 "

    e_str+= "_Enter _Enter"

    return e_str

def GetSTLSettings():
    eStr = "_ExportFileAs=_Binary "
    eStr+= "_ExportUnfinishedObjects=_Yes "
    eStr+= "_UseSimpleDialog=_No "
    eStr+= "_UseSimpleParameters=_No "
    eStr+= "_Enter _DetailedOptions "
    eStr+= "_JaggedSeams=_No "
    eStr+= "_PackTextures=_No "
    eStr+= "_Refine=_Yes "
    eStr+= "_SimplePlane=_No "
    eStr+= "_AdvancedOptions "
    eStr+= "_Angle=15 "
    eStr+= "_AspectRatio=0 "
    eStr+= "_Distance=0.01 "
    eStr+= "_Grid=16 "
    eStr+= "_MaxEdgeLength=0 "
    eStr+= "_MinEdgeLength=0.0001 "
    eStr+= "_Enter _Enter"
    return eStr

settingsList = {
    'GetDAESettings': GetDAESettings,
    'GetOBJSettings': GetOBJSettings,
    'GetSTLSettings': GetSTLSettings
}




fileName = rs.DocumentName()
filePath = rs.DocumentPath().rstrip(fileName)

arrLayers = layerNames(False)



def initExportByLayer(fileType="obj", visibleonly=False, byObject=False):
    for layerName in arrLayers:
        layer = scriptcontext.doc.Layers.FindByFullPath(layerName, True)
        if layer >= 0:
            layer = scriptcontext.doc.Layers[layer]
            save = True;
            if visibleonly:
                if not layer.IsVisible:
                    save = False
            if  rs.IsLayerEmpty(layerName):
                save = False
            if save:
                cutName = layerName.split("::")
                cutName = cutName[len(cutName)-1]
                objs = scriptcontext.doc.Objects.FindByLayer(cutName)
                if len(objs) > 0:
                    if byObject:
                        i=0
                        for obj in objs:
                            i= i+1
                            saveObjectsToFile(cutName+"_"+str(i), [obj], fileType)
                    else:
                        saveObjectsToFile(cutName, objs, fileType)



def saveObjectsToFile(name, objs, fileType):
    rs.EnableRedraw(False)
    if len(objs) > 0:
        settings = settingsList["Get"+fileType.upper()+"Settings"]()
        rs.UnselectAllObjects()
        for obj in objs:
            obj.Select(True)
        name = "".join(name.split(" "))
        command = '-_Export "{}{}{}" {}'.format(filePath, name, "."+fileType.lower(), settings)
        rs.Command(command, True)
        rs.EnableRedraw(True)


initExportByLayer("obj",True, False)
initExportByLayer("dae",True, False)
initExportByLayer("stl",True, False)

print "//export run ended/////////////"

This turned out to be simple. You need to supply a complete file path, name, and extension. The dialogs can be automated with multiple _Enter commands. In this script the default obj options are used. options can be appended to the _-Export command however before their respective _Enter commands are called.

import scriptcontext
import rhinoscriptsyntax as rs

def layerNames(sort=False):
    rc = []
    for layer in scriptcontext.doc.Layers:
        if not layer.IsDeleted: rc.append(layer.FullPath)
    if sort: rc.sort()
    return rc

fileName = rs.DocumentName()
filePath = rs.DocumentPath().rstrip(fileName)
extension = ".obj"

arrLayers = layerNames(False)

for layerName in arrLayers:
    objs = scriptcontext.doc.Objects.FindByLayer(layerName)
    if len(objs) > 0:
        rs.UnselectAllObjects()
        for obj in objs:
            obj.Select(True)
        scriptcontext.doc.Views.Redraw()
        rs.Command("_-Export "+filePath+layerName+extension+" _Enter _Enter")

In my notes I mentioned utilizing the mesh object and writing my own file via Python. This is still a viable option, but the method is not yet implemented on Mac for Rhino. I am now going to work on a recursive function to look for nested layers. I will post the solution to a Gist when complete.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM