During cooperation of large projects, I always encounter the situation like below:
Got a final large project model with numerous render materials from different designers, many blocks in it, and the goal is to make some rendering for presentation or simply add my part of model in it. There will be ten different glass materials, five grey colored materials, etc.
I always want to purge and rearrange the materials for simplication and better control.
There is an extension in Sketchup called material replacer that meet demand( The Fastest Way to REPLACE MATERIALS in SketchUp!). While in rhino, the way to do this is to:
- right click the material in material panel and hit ‘select objects’.
- right click another material for replacement and hit ‘assign to objects’.
The above action cannot affect objects in blocks or blocks of block which is very common in large projects. I also found topics like this, and they seems not solved yet:
So I wrote a script for this purpose, and the usage is like that of sketchup.
#!encoding:utf-8 # A simple script for global material replacement # It can replace all materials(including objects in blocks) of a model with another. # Since I havn't found out how to get the RenderMaterial of a subobject in (nested)blocks, # you can only pick objects outside blocks for the script to know the two material for replacement. import scriptcontext as sc import Rhino import rhinoscriptsyntax as rs def SelectObjs(prompt, preselect=True): go = Rhino.Input.Custom.GetObject() go.SetCommandPrompt(prompt) go.GeometryFilter = Rhino.DocObjects.ObjectType.Brep|Rhino.DocObjects.ObjectType.Mesh go.SubObjectSelect = False if not preselect: go.EnablePreSelect(False, False); go.DeselectAllBeforePostSelect = True; go.Get() if (go.CommandResult() == Rhino.Commands.Result.Success): return go.Object(0) return None def ChangeMat(Objects,RenderMat1,RenderMat2): for object in Objects: if type(object)!=Rhino.DocObjects.InstanceObject: if object.RenderMaterial!=None: if object.RenderMaterial.Name==RenderMat1.Name: object.RenderMaterial=RenderMat2 object.CommitChanges() else: idef=object.InstanceDefinition idefIndex=idef.Index RefObjects=idef.GetObjects() for obj in RefObjects: if type(obj)==Rhino.DocObjects.InstanceObject: ChangeMat([obj],RenderMat1,RenderMat2) else: if obj.RenderMaterial!=None: if obj.RenderMaterial.Name == RenderMat1.Name: obj.RenderMaterial=RenderMat2 obj.CommitChanges() newGeometry =  newAttributes =  for object in RefObjects: newGeometry.append(rs.coercegeometry(object)) ref = Rhino.DocObjects.ObjRef(object) attr = ref.Object().Attributes newAttributes.append(attr) InstanceDefinitionTable = sc.doc.ActiveDoc.InstanceDefinitions p=InstanceDefinitionTable.ModifyGeometry(idefIndex, newGeometry, newAttributes) def ReplaceMaterials(): RenderMat1=None while RenderMat1==None: object1 = SelectObjs('Select Material to replace',False).Object() RenderMat1 = object1.RenderMaterial RenderMat2=None while RenderMat2==None or RenderMat2.Name==RenderMat1.Name: object2 = SelectObjs('Select Material to replace with',False).Object() RenderMat2 = object2.RenderMaterial ObjectAll=sc.doc.Objects ChangeMat(ObjectAll,RenderMat1,RenderMat2) ReplaceMaterials()
I created an aliase for this script. Almost done.
But I havn’t found out how to get the RenderMaterial of a subobject in (nested)blocks. If it can get materials of objects in blocks, one will not have to make new material assigned objects outside blocks for the script to refer to.
So does anyone know how to refer to the subobject materials in blocks? I’ve tried set the ‘go.SubObjectSelect = True’ in my script and
to get the Index of the subobject, but still can’t reach the rendermaterial of the selected subobject. And the nested blocks will make it more complicated.