Create layers from material names

I have bought an obj model of a car, just to painfully discover that all meshes are on the same layer with about 30 different materials applied to them, hence my question:

Should it be possible by script (I can do some python) to select an object, take its material name, create a layer with that name and move the object to that layer?

This works here on separate meshes with standard rhino materials. No error proofing so could be dangerous. I’d open the obj in separate rhino file, run script, then copy it into your real file. If the entire car mesh is joined then it won’t work as it needs separate doc objects to change layer attribute. Also, if the materials are 3rd party render content, I’m not sure it will work.

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

guids = rs.GetObjects('select objects')

for guid in guids:
    obj = rs.coercerhinoobject(guid)
    material_index = obj.Attributes.MaterialIndex
    rhino_material = sc.doc.Materials[material_index]
    material_color = rhino_material.DiffuseColor
    material_name = rhino_material.Name
    print rhino_material.Name
    layer_index = sc.doc.Layers.Find(material_name, True)
    if layer_index >= 0:
        obj.Attributes.LayerIndex = layer_index
        obj.CommitChanges()
    else:
        new_layer_index = sc.doc.Layers.Add(material_name, material_color)
        obj.Attributes.LayerIndex = new_layer_index
        obj.CommitChanges()
2 Likes

10*6 thanks Nathan! Sorry for the late reply, was terribly busy with something els but I’m running now to try it!

Works like a CHARM!
Tried it on vray materials and the onlz concern is that it keeps the “/” that the plugin/rhino adds before the material name, but that’s no worrz. Either I delete it bz hand or even better I trz to tweak your code with my little python skills to have it done automatically.

Thanks again!!

Glad it worked!

1 Like

wow, thanks!
works perfectly

however would it be possible to make couple small adjustments?

  • on scripts run so not request to select objects - just create layers for all objects in the scene
  • skip (trim) “_material” from each layer name created

thank you very much

1 Like

Hi! I have been thinking that it is a really useful script! Also I was thinking if that’s for example possible to do same on Rhino Blocks? To make it open each one and assign the layers to material names accordingly? That would 100% solve most of my issues with models from different workflows.

python version:

creates layer based on object name, moves respective object to this layer.

in Rhino “EditPythonSCript”, paste code an run. Takes all available objects withoun prior manual selection.

# -*- coding: utf-8 -*-
import rhinoscriptsyntax as rs

def main():
    # get objects
    objs = rs.AllObjects()
    if not objs:
        print("no objects found ?!")
        return

    for obj in objs:
        # get obj name
        obj_name = rs.ObjectName(obj)
        if not obj_name:
            print("Object has no name, discarded:", obj)
            continue

        # if layer does not exist yet, create layer
        if not rs.IsLayer(obj_name):
            rs.AddLayer(obj_name)
            print("Create Layer:", obj_name)
        
        # move object to layer
        rs.ObjectLayer(obj, obj_name)
        print("if you like to move it, move it", obj, "in Layer", obj_name)

if __name__ == "__main__":
    main()

Script lets user create sublayers for further seperation: assign new sublayer name and select according objects, cycle through all layers. Prompt “stop” to cancel ooperation.

# -*- coding: utf-8 -*-
import rhinoscriptsyntax as rs
import scriptcontext as sc

def isolate_layer(layer_name):
    """Blendet alle Layer auĂźer 'layer_name' ein."""
    all_layers = rs.LayerNames()
    if not all_layers:
        return
    for lay in all_layers:
        rs.LayerVisible(lay, lay == layer_name)

def restore_all_layers():
    """Schaltet alle Layer wieder ein."""
    all_layers = rs.LayerNames()
    if not all_layers:
        return
    for lay in all_layers:
        rs.LayerVisible(lay, True)

def main():
    # Hole alle vorhandenen Layer
    layers = rs.LayerNames()
    if not layers:
        rs.MessageBox("Keine Layer vorhanden.", 0, "Fehler")
        return

    for main_layer in layers:
        objs = rs.ObjectsByLayer(main_layer)
        if not objs:
            continue  # Ăśberspringe leere Layer
        
        # Isoliere den aktuellen Hauptlayer
        isolate_layer(main_layer)
        rs.Redraw()
        print("Bearbeite Hauptlayer:", main_layer)
        
        while True:
            # Abfrage des Zusatznamens fĂĽr einen neuen Sublayer.
            # Hinweis: Mit ESC kann das gesamte Script abgebrochen werden.
            prompt = "Gib einen Zusatznamen fĂĽr einen Sublayer von '{}' ein (oder 'stop' zum Beenden)".format(main_layer)
            user_input = rs.StringBox(prompt)
            if user_input is None:
                # ESC gedrĂĽckt => Script abbrechen
                print("Script wurde abgebrochen.")
                restore_all_layers()
                return
            # Falls "stop" eingegeben wird, beende die Bearbeitung des aktuellen Layers.
            if user_input.strip().lower() == "stop":
                print("Beende Bearbeitung von Layer:", main_layer)
                break

            new_sublayer = "{}_{}".format(main_layer, user_input.strip())
            if not rs.IsLayer(new_sublayer):
                rs.AddLayer(new_sublayer)
                print("Neuer Sublayer erstellt:", new_sublayer)
            else:
                print("Sublayer '{}' existiert bereits.".format(new_sublayer))
            
            # Nutzer wählt nun die Objekte (Teilmeshes) aus, die in den neuen Sublayer verschoben werden sollen.
            sel_objs = rs.GetObjects("Wähle Objekte für Sublayer '{}' aus (ESC zum Abbrechen)".format(new_sublayer), preselect=True)
            if sel_objs is None:
                # ESC gedrückt während der Objektauswahl => komplettes Abbrechen des Scripts
                print("Script wurde abgebrochen während der Objektauswahl.")
                restore_all_layers()
                return
            
            # Verschiebe die ausgewählten Objekte in den neuen Sublayer
            for obj in sel_objs:
                rs.ObjectLayer(obj, new_sublayer)
                print("Objekt {} in Sublayer {} verschoben.".format(obj, new_sublayer))
            rs.Redraw()
            
        # Nachdem alle Sublayer fĂĽr den aktuellen Hauptlayer angelegt wurden, werden alle Layer wieder eingeblendet.
        restore_all_layers()
        rs.Redraw()
    
    print("Sublayer-Erstellung abgeschlossen.")

if __name__ == "__main__":
    main()