Setting Colors in Fusion 360 Using Appearances

There was a recent question on the Fusion 360 Customization forum about using an RGB value to set the color of a body.  Fusion 360 only allows you to assign an appearance to a body, occurrence, or face.  You can’t just assign an RGB value but you can assign an appearance that is the color you want.  Another limitation with appearances in Fusion 360 is that you can’t create a new appearance from scratch but instead, you create a new appearance by copying an existing one.  And one final limitation is that to use an appearance it must exist in the design; you can’t directly use an appearance from a library.  It all seems a bit complicated, and I would agree, but below is some example code that works around these issues to create a new appearance that’s red in color and assigns it to a selected body.

ui = None
try:
    app = adsk.core.Application.get()
    ui  = app.userInterface
    design = adsk.fusion.Design.cast(app.activeProduct)

    body = adsk.fusion.BRepBody.cast(ui.selectEntity('Select a body', 'Bodies').entity)

    # Check to see if the "MyRedColor" exists in the local appearances.
    favoriteAppearances = design.appearances
    try:
        myColor = favoriteAppearances.itemByName('MyRedColor')
    except:
        myColor = None

    if myColor:
        body.appearance = myColor
    else:
        # Get the existing Yellow appearance.            
        fusionMaterials = app.materialLibraries.itemByName('Fusion 360 Appearance Library')
        yellowColor = fusionMaterials.appearances.itemByName('Paint - Enamel Glossy (Yellow)')
        
        # Copy it to the design, giving it a new name.
        newColor = design.appearances.addByCopy(yellowColor, 'MyRedColor')
                    
        # Change the color of the appearance to red.
        colorProp = adsk.core.ColorProperty.cast(newColor.appearanceProperties.itemByName('Color'))
        colorProp.value = adsk.core.Color.create(255, 0, 0, 0)

        # Assign it to the body.            
        body.appearance = newColor
except:
    if ui:
        ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

The code above first checks to see if there is already an appearance called “MyRedColor” in the design.  If it already exists, it uses it.  If it doesn’t, then it copies the appearance named “Paint – Enamel Glossy (Yellow)” from the “Fusion 360 Appearance Library” into the design and as part of the copy operation, it names the copy to “MyRedColor”.  It then edits the color of the new appearance to a red color and assigns it to the body.

To make the above work, I had to first find an appearance that was close to what I wanted, except for the color.  For example, do you want something that is transparent or opaque?  How shiny should it be?  There are a lot of settings that control how something is rendered.  These settings allow for some nice renderings but also significantly complicate things when you just want something to be red or yellow or blue.  Once you’ve identified an existing appearance that is similar to what you want, you can modify the code above to copy that appearance from the library and change its properties to be the way you want it.

Appearances are quite complex and have a lot of settings that control how they render.  One of the reasons I chose the paint appearance is because it is a simpler appearance and is mostly defined by a single color.  In the example above, I’m getting a property from the appearance that’s named “Color” and using an RGB value to set it.  Not all types of appearances will have the same properties.  The best way to determine what an appearance supports is to edit in the user interface and click the “Advanced” button to see all of the settings.  You can see the result from various appearances below and how they have very different properties.

The edit dialog gives you a nice view of what’s available but then you need to be able to access and change those values using the API.  Each appearance is really just a list of properties of various types.  The script below will dump information about all the appearances into a text file.  You can use this to determine the specific properties of an appearance that you might want to edit.  Running the script below will create a big file and it isn’t even dumping out all of the information that is available but should be enough detail in most cases. You can find the appearance in the file and determine the names of the properties that you need to edit.  Then by using code similar to the first program above you can do a bit of trial and error to determine the values to use when setting the properties of the appearance.

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        design = adsk.fusion.Design.cast(app.activeProduct)

        result = ''
        cnt = 0
        
        # Iterate through all of the appearances in all of the libraries.
        lib = adsk.core.MaterialLibrary.cast(None)
        for lib in app.materialLibraries:
            result += 'Library "' + lib.name + '"\n'
            appear = adsk.core.Appearance.cast(None)
            for appear in lib.appearances:
                result += '   Appearance "' + appear.name + '"\n'
                
                prop = adsk.core.Property.cast(None)
                for prop in appear.appearanceProperties:
                    cnt += 1
                    result += '      Property\n'
                    result += '         Name: ' + prop.name + '\n'
                    result += '         Id: ' + prop.id + '\n'
                    result += '         Type: ' + prop.objectType + '\n'
                    
                    if prop.objectType == adsk.core.AppearanceTextureProperty.classType():
                        txtProp = adsk.core.AppearanceTextureProperty.cast(prop)
                        val = ''
                        try:
                            val = str(txtProp.value)
                        except:
                            val = 'Failed to get value.'
                        result += '         Value: ' + val + '\n'
                    elif prop.objectType == adsk.core.IntegerProperty.classType():
                        intProp = adsk.core.IntegerProperty.cast(prop)
                        result += '         Value: ' + str(intProp.value) + '\n'
                    elif prop.objectType == adsk.core.ColorProperty.classType():
                        if cnt == 931:
                            i = 55
                        colorProp = adsk.core.ColorProperty.cast(prop)
                        val = colorProp.value
                        if val:
                            result += '         Value: ' + (str(val.red) + ',' +
                                                            str(val.green) + ',' +
                                                            str(val.blue) + ',' +
                                                            str(val.opacity) + '\n')
                        else:
                            result += '         Value: Undefined\n'                                
                    elif prop.objectType == adsk.core.StringProperty.classType():
                        strProp = adsk.core.StringProperty.cast(prop)
                        result += '         Value: ' + strProp.value + '\n'
                    elif prop.objectType == adsk.core.FloatProperty.classType():
                        floatProp = adsk.core.FloatProperty.cast(prop)
                        result += '         Value: ' + str(floatProp.value) + '\n'
                    elif prop.objectType == adsk.core.BooleanProperty.classType():
                        boolProp = adsk.core.BooleanProperty.cast(prop)
                        result += '         Value: ' + str(boolProp.value) + '\n'
                    elif prop.objectType == adsk.core.ChoiceProperty.classType():
                        choiceProp = adsk.core.ChoiceProperty.cast(prop)
                        result += '         Value: ' + str(choiceProp.value) + '\n'
                        (returnValue, names, choices) = choiceProp.getChoices()
                        result += '         Choices: \n'
                        for i in range(len(names)):
                            result += '            ' + names[i] + ', ' + choices[i] + '\n'
                    else:
                        result += '         ****** Unsupported Type ******\n'
                        
        output = open('c:\\temp\\FusionAppearances.txt', 'w')
        output.writelines(result)
        output.close()
        ui.messageBox('Finished wrting to c:\\temp\\FusionAppearances.txt')
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()) + ', ' + str(cnt))    

The approach I use is to use the user interface to find an appearance that’s close to what you want and then use with the Edit dialog to determine if the kind of edits I want to make are possible.

 

5 thoughts on “Setting Colors in Fusion 360 Using Appearances”

  1. How can we set the ‘image’ instead the ‘color’ for the material? I try to analize log-file from your last example and found several variants of property ‘Image’ and ‘urn’ for each material. But how can we us them?

    Reply
    • Working with the materials is quite difficult because of all of the non-intuitive settings. The best thing to do is to run the program on the material you want to edit, then edit it in the UI to make the desired changes, and then run the program again and look for what’s different between the two results. That way you know what to change and how to change it.

      Reply
  2. This is great. One question though: If your code is written in English and then run on a machine, in Spanish, for example. Will the lines of code:
    fusionMaterials = app.materialLibraries.itemByName(‘Fusion 360 Appearance Library’)
    yellowColor = fusionMaterials.appearances.itemByName(‘Paint – Enamel Glossy (Yellow)’)
    crash since they are hard coded in English?

    Reply

Leave a Comment