It’s been a while since the last time that I was looking at Materials in Dynamo. Literally more than 5 years. Here’s the last write up I did on that subject: Materials Guess what? Revit APIs don’t change…or so I thought. Well, let’s not give Revit developers too much credit here, but I was a little surprised to see that some things were added to the Revit API around Materials. Some are just weird, but for the most part it moved in the positive direction.
Anyways, so I was asked to pull together an example of how would one use Dynamo to create Materials in Revit from something like an Excel spreadsheet. Mhmmmmm. You could probably do this already back in the days, by simply making copies of the Material, but now we have a spanking new API, that allows us to “create” new Materials. Well, it’s not that new, but 2018+ versions of Revit have it so I was happy. Great. I wanted to set some properties on said Materials. Can I do that too? Yes, now we have APIs for creating new AppearanceAssetElements. Damn! Autodesk, what have gotten into you guys. OK, last one. What if I wanted to set the Rendering Appearance Asset so that I can use the fancy rendering properties like Reflectivity or Bump? Can I do that? Nope. For that one you still have to copy an existing AppearanceAssetElement. To be precise the AppearanceAssetElement is not an issue. There is an API to create one, but in order to control its Rendering Asset properties, we need to create an Asset, and that’s not something we can do. Back to duplicating existing objects. I guess I should have expected that. Thanks Autodesk.
Here’s the script as put together:
In order to create this script I ended up creating quite a few new components that were added to archi-lab.net package. Here’s a few comments about that:
- Materials.Create – this creates a new empty Material. All we need to create a new Material is a name – preferable unique.
- Materials.UseRenderAppearanceForShading – this is needed for us to override a default value. Revit doesn’t normally use Render Appearance Asset for shading, and when it’s disabled, in version 2018, for example it doesn’t even create the AppearanceAssetElement for it. It only gets created when we turn this on.
- AppearanceAssets.CreateViaDuplicate – this is the most important node in this script. Everything hinges on this node being able to find a “Default” Material. Every Revit file should have a material named Default, but just in case yours doesn’t please make sure to add one before using this node. I know I suck. Now, that I am thinking about this, I should have exposed an input for this. Ahhh…next time. Here’s the code for reference:
As you can see above the code is a little hacky, that’s why I wanted to share this. So in order to duplicate an AppearanceAssetElement we need a new name for object that would result from such operation. It has to be unique too, and since there is no static utility anywhere to check if proposed name is unique, we have to do a little try/catch inside of a while loop, or use the “goto”. I haven’t used a goto in a while so here we are.
- AppearanceAssets.SetGenericProperties – this node allows you to set color, glossiness, and whether a material is metallic or not. It comes from these properties in Revit:
There is a little cool thing worth knowing about setting Asset properties. Yes, Revit doesn’t exactly make that straight forward. First, the properties on an asset are stored in an array. They have some fancy names, and special types for setting them. Here’s how to obtain the value for Color for example:
Revit Lookup to the rescue. There is no good way to find out what we are looking for. I just had to look through these property arrays to sort out that Color is stored under DoubleArray4d. It’s name is really “generic_diffuse”. Once you have that info you can run the following code to set that info on an Asset:
Other properties that we are setting here like “glossiness” is also not very straight forward because in UI Glossiness is defined as a value between 0-100. That would normally suggest that we are dealing with an integer. Couldn’t be further from truth. Glossiness is actually stored as a double, remapped from 0-100 range into 0-1. It’s pretty simple, just divide by 100, but still…why?
- Materials.SetAppearanceAsset – nothing special here. We can use that node to set the AppearanceAssetElement on our newly created Material.
- Materials.SetMaterialClass – just a string value that we can use to categorize our materials.
- Materials.SetSurfacePattern – this sets the Surface Pattern. One trick here, is that the Fill Pattern that we want to use kind of has to exist in the model, unless we want to go into a whole new can of worms around creating Fill Patterns. If we assume that the Fill Pattern exists then we can just find it by its name. I added a few utility nodes for that.
- FillPatterns.Exists – returns true if Fill Pattern with a given name exists otherwise false.
- FillPattern.GetByName – returns a Fill Pattern with the given name.
When it comes to Fill Patterns please be aware that Revit 2018 will ship with a different set of them pre-loaded than let’s say Revit 2021. Just FYI. If your intent is to create Materials from an Excel spread sheet, you might have to keep a different version of the Excel for different versions of Revit.
Another gotcha moment that I already mentioned was that when you make a new model in Revit 2018, it will have some default Materials loaded into it. None of these Materials uses Rendering Appearance Assets, and hence none of them are created in the file. It’s weird, but basically you have to make sure that it exists first before trying to use one to create a duplicate of it.
Other than, that it looks like there were some improvements to the Revit API in the recent years. I definitely appreciate that as a developer. Could they have been better? Yes, it feels like the API around Materials is still not complete, and lacks crucial functionality especially for dealing with Assets. There is literally nothing in the API for Asset class. That’s a downer. Overall, with a little stretching, one can accomplish some basic tasks around Materials, so it’s all good.
Please let me know if you have any comments.
Thanks to Oliver Green we now have a complete reference of Asset property names to use with out scripts. One thing worth mentioning is that at the moment, I only exposed a handful of them via nodes in Dynamo, so unfortunately the full list is a great reference for those willing to jump in and get their hands dirty with some coding. It will not be very helpful for Dynamo users at the moment. If I am ever looking into Materials again, I might jump in there and include a few more of these. Don’t hold your breath here though. Either way, Oliver, thanks for sharing!