Changing material texture path with editScope

Changing material texture path with editScope

lukaskohout
Advocate Advocate
4,874 Views
17 Replies
Message 1 of 18

Changing material texture path with editScope

lukaskohout
Advocate
Advocate

Hello all,

I am trying to set material texture path using following code (Revit 2018):

public void ChangeRenderingTexturePath(Material mat, Document doc, string texturePath)
        {            
            AppearanceAssetElement appearanceAsset = (AppearanceAssetElement)doc.GetElement(mat.AppearanceAssetId);
            Asset renderingAsset = appearanceAsset.GetRenderingAsset();

            int size = renderingAsset.Size;
            for (int assetIdx = 0; assetIdx < size; assetIdx++)
            {            
                AssetProperty aProperty = renderingAsset[assetIdx];

                if (aProperty.NumberOfConnectedProperties < 1)
                    continue;

                Asset connectedAsset = aProperty.GetConnectedProperty(0) as Asset;
                if (connectedAsset.Name == "UnifiedBitmapSchema")
                {
                    AssetPropertyString path = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap) as AssetPropertyString;                    

                    using (AppearanceAssetEditScope editScope = new AppearanceAssetEditScope(doc))
                    {
                        Asset editableAsset = editScope.Start(mat.AppearanceAssetId);   
// Exception thrown, asset is read only, need to use editScope path.Value = texturePath; editScope.Commit(true); } } }

I know that editScope accepts only ElementId (specifically AppearanceElementAsset.Id), but with this I can not get to edit the texture path that is saved in RenderingAsset of the AppearanceAsset.

 

Do anyone know any way to get around this?

Finally we can create materials with API but without textures? Does not make sense.

 

Thanks.


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Accepted solutions (1)
4,875 Views
17 Replies
Replies (17)
Message 2 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukáš,

 

Thank you for your query.

 

Are you working in the updated version of Revit 2018 which includes the asset editing functionality?

 

http://thebuildingcoder.typepad.com/blog/2017/11/modifying-material-visual-appearance.html

 

Furthermore, have you seen this article on accessing the material texture path?

 

http://thebuildingcoder.typepad.com/blog/2017/10/material-texture-path.html

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 3 of 18

lukaskohout
Advocate
Advocate

Dear Jeremy,

I am using the latest Revit 2018 API with asset editing. I am able to duplicate and edit AppearanceAsset.

I have search your whole blog and read both the posts you suggested - the way I obtain the current texture path is taken directly from one of those two posts.

 

Problem with the texture path as I see it is, that it is not directly contained in the AppearanceAsset but in the connected RenderingAsset. And to that I cannot get through the EditScope. RenderingAsset has no ElementId and cannot be used in AppearanceAssetEditScope.Start() function.

 

Exception message:

An exception of type 'Autodesk.Revit.Exceptions.InvalidOperationException' occurred in RevitAPI.dll but was not handled in user code.
Additional information: The asset property is not editable. Asset can be edited only in an edit scope.

Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 4 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukáš,

 

Thank you for your update and clarification.

 

I passed it on to the development team and hope they can clarify this for you.

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 5 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukáš,
 
The development team reply:
 
The only editable Asset inside the edit scope is the one returned from `AppearanceAssetEditScope.Start`, and those connected Assets which it directly returns.
 
I think if the customer reverses their code and get the UnifiedBitmapSchema from the returned asset from `Start`, they will be able to change it.
 
Best regards,
 
Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 6 of 18

lukaskohout
Advocate
Advocate

Dear Jeremy,

 

thanks for quick response. I tried proposed solution. Unfortunately still no success.

Problem is that the returned Asset from AppearanceAssetEditScope.Start does not containt the desired UnifiedBitmatSchema property. That property is containd only in the RenderingAsset.

 

 


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 7 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukáš,

 

Thank you for your update and sorry to hear it did not work out.

 

I asked the development team why, and they reply:

 

That certainly doesn't sound right.  Can you please provide the modified source code that didn't work?

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 8 of 18

lukaskohout
Advocate
Advocate

Of course Jeremy.

At first I tried simply this:

using (AppearanceAssetEditScope editScope = new AppearanceAssetEditScope(doc))
{
    Asset editableAsset = editScope.Start(mat.AppearanceAssetId);

    for (int assetIdx = 0; assetIdx< 100; assetIdx++)
    {

        AssetProperty aProperty = editableAsset[assetIdx];

        if (aProperty.NumberOfConnectedProperties< 1)
            continue;

        Asset connectedAsset = aProperty.GetConnectedProperty(0) as Asset;
        if (connectedAsset.Name == "UnifiedBitmapSchema")
        {
            AssetPropertyString path = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap) as AssetPropertyString;
            path.Value = Convert.ToString(texturePath);
        }
    }
    editScope.Commit(true);
}

This resulted in this list of properties for this Asset (listed down on the page):

http://adndevblog.typepad.com/aec/2015/03/revitapi-how-to-get-asset-properties-of-material-i-want.ht...

 

Then I tried this:

using (AppearanceAssetEditScope editScope = new AppearanceAssetEditScope(doc))
{
    Asset editableAsset = editScope.Start(mat.AppearanceAssetId);
    AppearanceAssetElement appearanceAsset = (AppearanceAssetElement)doc.GetElement(mat.AppearanceAssetId);
    Asset renderingAsset = appearanceAsset.GetRenderingAsset();                
               
    foreach(var property in editableAsset.GetAllConnectedProperties())
    {
        if (property.NumberOfConnectedProperties< 1)
            continue;

        Asset connectedAsset = property.GetConnectedProperty(0) as Asset;
        if (connectedAsset.Name == "UnifiedBitmapSchema")
        {
            AssetPropertyString path = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap) as AssetPropertyString;
            path.Value = Convert.ToString(texturePath);
        }
    }
    editScope.Commit(true);
}

But method GetAllConnectedProperties() returns empty List<>.

 

I really do not know waht else to try since I am still quite new to Revit API.

Could the DEV team point me somewhere?

 

Thanks in advance.

Lukas


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 9 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukas,

 

Thank you for your update and sample code.

 

The development team took a look at it and say:

 

There's some strangeness about looking at assets, at what is, essentially, random, and hoping to find the one you want.

 

I'd recommend starting from the code snippet which shows how to do this.

 

It is available from the help documentation on `GetSingleConnectedAsset`:

 

http://www.revitapidocs.com/2018.1/3a190829-9269-0e56-8b9b-a53b89de35a6.htm

 

Please let us know how you resolve this, since it may be of interest to others as well.

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 10 of 18

lukaskohout
Advocate
Advocate
Accepted solution

Thanks Jeremy. Finally I got it to work. It was quite simple actually in the end. There is just one small change from the code snippet I posted at first.

I just changed the search from renderingAsset to the editableAsset.

        public void ChangeRenderingTexturePath(Material mat, Document doc, string texturePath)
        {
            using (AppearanceAssetEditScope editScope = new AppearanceAssetEditScope(doc))
            {
                Asset editableAsset = editScope.Start(mat.AppearanceAssetId);               

#if VERSION2018
                AssetProperty assetProperty = editableAsset["generic_diffuse"];
#else
                // VERSION2019
                AssetProperty assetProperty = editableAsset.FindByName("generic_diffuse");
#endif
                Asset connectedAsset = assetProperty.GetConnectedProperty(0) as Asset;
                if (connectedAsset.Name == "UnifiedBitmapSchema")
                {
                    AssetPropertyString path = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap) as AssetPropertyString;
                    if (path.IsValidValue(texturePath))
                        path.Value = texturePath;
                }                

                editScope.Commit(true);
            }
        }

I hope that someone find this useful.

 

Lukas


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
Message 11 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukas,

 

Thank you for your update and congratulations on getting it to work!

 

I hope that others find this useful too, and I am sure they will.

 

In order to support that, could you possibly provide a minimal reproducible case how to achieve the task, changing the material texture path with the editScope?

 

http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b

 

It would not have to be much, I think. Probably just a minimal little sample model with a single wall or other element making use of a rendering asset and the code showing how to change its texture path as described above will be perfectly sufficient.

 

Thank you!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes
Message 12 of 18

lukaskohout
Advocate
Advocate

Dear Jeremy,

 

once again thanks for your input.

Below you can download archive with sample Visual Studio solution with detailed guide as well as with sample project and texture.

 

Lukas


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 13 of 18

Anonymous
Not applicable

Hi @lukaskohout  I have a problem... I create a material using the following code.

 

  // Create new material
                var newMaterial = Material.Create(doc, "Marmol");
                var material = doc.GetElement(newMaterial) as Material;

When trying to implement your code, it does not allow me to change the texture and throws me an exception.  (System.NullReferenceException) Apparently this occurs because when creating a material it does not have a default texture therefore it can not be changed because it recovers a null value.  Any idea how to create a material with a texture by default?  Or How to add texture even if the path comes empty?  I hope you can help me, regards...

 

 

0 Likes
Message 14 of 18

lukaskohout
Advocate
Advocate

Hello,

well first thing I would check is if the material you are duplicating in Material.Create() method is of category that even allows textures. Some material, like glass for example, do not have textures. Therefore I would check if the generic_diffuse property exists.

 

Hope this helps.

 


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 15 of 18

Anonymous
Not applicable

Yes, I can manually add the texture. The problem is that when I create the material, it does not have a default image...

 

Untitled.png

By not having a selected image, it does not allow me to change the texture with the code you have implemented. My idea is to create the material and load the texture at the same time. I hope my query is clear and you can help me.

0 Likes
Message 16 of 18

lukaskohout
Advocate
Advocate

Well, I actually never tried that as I always had a texture assgined. Is it big issue for you to create some "TEMPLATE" material that will have the texture? Even if it uis empty image or something? The Material.Create() method always takes some template material which it is duplicating to create new one. Do not forget to duplicate the AppearanceAsset as well so you would not have the texture and information for multiple materials.

 

I think that the problem is, that the asset editing only works with what is already there (meaning connected assets and properties) and I could not find a way how to add some property since there is no AddConnectedProperty method for the Asset.

 


Hitting Accepted Answer is a Community Contribution from me as well as from you.
======================================================================
0 Likes
Message 17 of 18

Anonymous
Not applicable

Ok @lukaskohout  thanks a lot for the help. I will keep trying, I hope to get it, if you find some way I would appreciate it if you would inform me. Regards.

0 Likes
Message 18 of 18

jeremytammik
Autodesk
Autodesk

Dear Lukas,

 

Thank you very much indeed for your valuable sample material!

 

Please excuse the long delay in taking a closer look at it.

 

I finally got around to it now and published it here on The Building Coder for better visibility and readability:

 

https://thebuildingcoder.typepad.com/blog/2019/04/set-material-texture-path-in-editscope.html

 

Thank you ever so much again!

 

Cheers,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

0 Likes