[BUG?] Problem with Materials and unlinked Appearance Assets

[BUG?] Problem with Materials and unlinked Appearance Assets

Anonymous
Not applicable
2,509 Views
10 Replies
Message 1 of 11

[BUG?] Problem with Materials and unlinked Appearance Assets

Anonymous
Not applicable

I'm working with the Revit 2015-2018 APIs, and this problem manifests itself with all versions.

 

Within my plugin, I'm getting a Material, AppearanceAsset and then the Asset itself to determine the appearance properties thus :-

 

Material material = document.GetElement(materialid) as Material;

AppearanceAssetElement appearance = document.GetElement(material.AppearanceAssetId) as AppearanceAssetElement;

Asset asset = appearanceElem.GetRenderingAsset();

 

However, for some Materials, the AppearanceAssetId is set to {-1}, so effectively there is no AppearanceAssetElement or Asset to fetch, as per the MaterialDebug.png

 

But, when I open the Materials Panel in Revit, the Material clearly has an Appearance Asset & Assets defined, as per the MaterialPanel.png.

 

Is this a bug in the API, or is there some other mechanism by which a Material and Appearance Asset are linked together?

 

This makes absolutely no sense to me. It only manifests itself for certain materials, but behaves consistently across multiple trials.

0 Likes
Accepted solutions (1)
2,510 Views
10 Replies
Replies (10)
Message 2 of 11

Anonymous
Not applicable

Sorry, small mistake in my code sample.

 

Asset asset = appearance.GetRenderingAsset();

0 Likes
Message 3 of 11

Mustafa.Salaheldin
Collaborator
Collaborator

Dear Dave

 

It seems like you are using a German version of Revit Material Library, I don't want to blame the version language in first place for your code not working fine instead I guess you are missing something. I've written a complete sample code for you that demonstrates how I retrieve the material then its Id and then get the required assets. It is based on your original code, but you didn't show how you get the Material Id in first place.

 

Here is a screenshot from my result for "Concrete, Cast In Situ" which I believe is the translation of "stahlbeton - ortbeton" (if I'm not mistaken).

 

material.PNG

I guess this is the problem, maybe you are missing something.

 

#region Namespaces

using System;
using System.Linq;
using Autodesk.Revit.Attributes;

using Autodesk.Revit.DB;

using Autodesk.Revit.UI;

using Autodesk.Revit.Utility;

using RvtApplication = Autodesk.Revit.ApplicationServices.Application;
using RvtDocument = Autodesk.Revit.DB.Document;

#endregion

namespace Atkins
{
    [Transaction(TransactionMode.Manual)]
    [Regeneration(RegenerationOption.Manual)]
    public class MaterialsAsset : IExternalCommand
    {
        #region Cached Variables

        private static ExternalCommandData _cachedCmdData;

        public static UIApplication CachedUiApp
        {
            get
            {
                return _cachedCmdData.Application;
            }
        }

        public static RvtApplication CachedApp
        {
            get
            {
                return CachedUiApp.Application;
            }
        }

        public static RvtDocument CachedDoc
        {
            get
            {
                return CachedUiApp.ActiveUIDocument.Document;
            }
        }

        #endregion

        #region IExternalCommand Members         

        public Result Execute(ExternalCommandData cmdData, ref string msg, ElementSet elemSet)
        {
            _cachedCmdData = cmdData;

            try
            {
                //TODO: add your code below.

                FilteredElementCollector collector = new FilteredElementCollector(CachedDoc);
                var materials = collector.WherePasses(new ElementClassFilter(typeof(Material))).Cast<Material>();

                Material mat = materials.Cast<Material>().Where(m => m.Name == "Concrete, Cast In Situ").FirstOrDefault();

                Material material = CachedDoc.GetElement(mat.Id) as Material;

                AppearanceAssetElement appearance = CachedDoc.GetElement(material.AppearanceAssetId) as AppearanceAssetElement;

                Asset asset = appearance.GetRenderingAsset();

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                msg = ex.ToString();
                return Result.Failed;
            }
        }

        #endregion
    }
}

Please if this reply solved your problem don't forget to mark it as an answer, otherwise please provide more sample code on how you are trying to get the elements.


¯\_(ツ)_/¯
Let it work like a charm.

Mustafa Salaheldin


EESignature




Digital Integration Manager, DuPod

Facebook | Twitter | LinkedIn

0 Likes
Message 4 of 11

Anonymous
Not applicable

I'm actually using the CustomExporter and collecting a set of materialid(s) used on elements in the drawing.

 

I'm using the US version of Revit, it just so happens the drawing I'm testing is from a German company - thus the German names. However, the naming conventions should be irrelevant as all the objects are organized / linked by IDs.

 

My whole issue is that once I've got a Material object using the call

 

Material material = document.GetElement(materialid) as Material;

 

sometimes the AppearanceAssetID is {-1} ... most materials I get the same output as in your screenshot, where the AppearanceAssetID has some positive value, which allows the lookup of the AppearanceAsset and then the actual Asset itself.

 

But if the AppearanceAssetID == -1, that's effectively a null / empty / non-linked object. But in the Materials Panel of Revit, that Material clearly does have an AppearanceAsset linked to it.

 

The only thing I can think of right now is that perhaps using a FilteredElementCollection and your method of casting somehow gives different results than my method of using document.GetElement(id) as Material, but I'm not optimistic.

 

I'll update if I make any progress, and thank you for your assistance.

0 Likes
Message 5 of 11

Mustafa.Salaheldin
Collaborator
Collaborator

Can you post a sample file with the material that causes the problem?


¯\_(ツ)_/¯
Let it work like a charm.

Mustafa Salaheldin


EESignature




Digital Integration Manager, DuPod

Facebook | Twitter | LinkedIn

0 Likes
Message 6 of 11

Anonymous
Not applicable

Unfortunately that presents me with a problem, as it's the IP of the company, and I don't really want to post it publically.

 

However, something you mentioned about languages got me thinking.

 

As I said, when inspecting the Material via the API, the AppearanceAsset is -1, implying no currently linked Asset.

 

The Material has the following properties :-

 

MaterialCategory : "Beton"

MaterialClass : "Beton"

Name : "Stahlbeton - Ortbeton"

 

Which are German names for concrete.

 

Now when I look in the Materials Panel in Revit, or indeed do a render, it appears to be assigning an Appearance on the fly, with the name (in English)

 

"Non-Uniform - Warm Grey"

 

Which is one of the predefined types in the Appearance Library for a concrete category and class.

 

So it appears that when an AppearanceAsset for a Material is marked as {-1}, it must be trying to guess a suitable one, based on the MaterialCategory, MaterialClass and possibly also the Name?

 

Of course, then the question becomes, are the German names mapped to English somewhere, or are there encoded parameters in the Material.Parameters or Material.ParameterMap that possibly are enums of the Category and Class information.

 

In which case, why would the "Non-Uniform - Warm Grey" be the one he selected on the fly from all the possible concrete ones? Is it random, or is there some basis on the Name of the material also?

 

Whatever is happening on the fly is still not reflected in the API interface, so I think it's just a case of working out how he guesses which Appearance to apply based on those category, class and possibly also the name.

 

Very sleepy now, so I'll try again tomorrow. I'll also try to find a "non-sensitive" file that exhibits the same behaviour so you can see for yourself the issue.

 

(EDIT: I'll also have a look in the CustomExporter, as I seem to remember some function available on MaterialNodes that might tell us what Appearance is being applied on the fly).

 

Regards

Dave

0 Likes
Message 7 of 11

Anonymous
Not applicable

Just an update before I close the topic. It might serve useful for others in future.

 

I discovered that in the CustomExporter, the OnMaterial callback gives us access to a MaterialNode, and calling the node.GetAppearance() at least exposes the LibraryName and Name of the Asset he's decided to use. At this point, it seems he's already performed his "guess" on what to use.

 

So I just create a dictionary using the original materialid as the key, and the concatted LibraryName and Name as the value.

 

Later, I can lookup the Asset in the SystemAssets collection by LibraryName and Name, and use it whenever the regular API Material doesn't expose an AppearanceAssetId.

 

        Dictionary<int,string> master_mat2app = new Dictionary<int,string>();

 

        public void OnMaterial(MaterialNode node)
        {
            materialid = node.MaterialId.IntegerValue;
            if (!master_mat2app.ContainsKey(materialid))
            {
                var app = node.GetAppearance();
                master_mat2app.Add(materialid, app.LibraryName + "|||" + app.Name);
            }
        }

 

Mustafa, thanks for your time on this matter.

 

I swear this API is more painful than having wisdom teeth removed!

0 Likes
Message 8 of 11

Mustafa.Salaheldin
Collaborator
Collaborator
Accepted solution

No worries. So my guess was right about the language of the Material library.

Any way if your issue is solved please close the topic by marking the reply as an answer.


¯\_(ツ)_/¯
Let it work like a charm.

Mustafa Salaheldin


EESignature




Digital Integration Manager, DuPod

Facebook | Twitter | LinkedIn

0 Likes
Message 9 of 11

michael-coffey
Advocate
Advocate

I am encountering this same problem, but I'm not using the CustomExporter so I can't use this workaround.  I am iterating through the materials to test which are using the "new" appearance assets.  When I come across a material that has an AppearanceAssetId of -1, then I can't tell what Appearance Asset has been 'randomly' assigned.  The example in the help document for Material.AppearanceAssetId Property doesn't make sense because you need the Asset in order to match it up with the "system assets".  You can't get the Asset without having a valid AppearanceAssetId  first.  I've attached a sample file to show materials where AppearanceAssetId is -1.  DynamoError and all of the materials that start with "Render Material".  Thanks.

0 Likes
Message 10 of 11

ameer.mansourWAK8Y
Advocate
Advocate

what if i want to get

AppearanceAssetElement 

from material that in a linked file?

0 Likes
Message 11 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @ameer.mansourWAK8Y ,

 

I have a suggestion. Please explore the material in the linked file via the RevitLookup tool.

I tested by creating a wall in a document and applying the material to one of the wall faces. I then linked this document into another document.

I am able to access the Appearance Asset of the material in the linked file.

Could you please provide some more information?


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes