public static List <TextureBundle> GetTextureBundles(Document doc, out List <string> paths) { if (_bundleCache.ContainsKey(doc.PathName)) { paths = _texturePathCache[doc.PathName]; return(_bundleCache[doc.PathName]); } _texturePathCache.Add(doc.PathName, new List <string>()); // Find materials FilteredElementCollector fec = new FilteredElementCollector(doc).OfClass(typeof(Material)); // Convert materials to bundles List <TextureBundle> bundles = new List <TextureBundle>(); foreach (var m in fec.Cast <Material>()) { try { var bundle = new TextureBundle(m); ElementId appearanceAssetId = m.AppearanceAssetId; AppearanceAssetElement appearanceAssetElem = doc.GetElement(appearanceAssetId) as AppearanceAssetElement; if (appearanceAssetElem == null) { continue; } Asset asset = appearanceAssetElem .GetRenderingAsset(); if (asset == null) { continue; } for (int assetIdx = 0; assetIdx < asset.Size; assetIdx++) { AssetProperty aProperty = asset[assetIdx]; if (aProperty.NumberOfConnectedProperties < 1) { continue; } Asset connectedAsset = aProperty .GetConnectedProperty(0) as Asset; // See if there is a path associated. #if REVIT2018 || REVIT2019 || REVIT2020 // This line is 2018.1 & up because of the // property reference to UnifiedBitmap // .UnifiedbitmapBitmap. In earlier versions, // you can still reference the string name // instead: "unifiedbitmap_Bitmap" AssetPropertyString path = connectedAsset[ UnifiedBitmap.UnifiedbitmapBitmap] as AssetPropertyString; #else AssetPropertyString path = connectedAsset["unifiedbitmap_Bitmap"] as AssetPropertyString; #endif // If there is no asset path, nothing to pursue (Empty field) if (path == null || String.IsNullOrEmpty(path.Value)) { continue; } // See what kind of texture it is. if (TryGetTextureTypeFromAssetName(connectedAsset.Name, out var t)) { // This will be a relative path to the // built -in materials folder, addiitonal // render appearance folder, or an // absolute path. string assetName = Path.GetFileNameWithoutExtension(path.Value); // Ensure that we have a valid texture path. if (RevitTextures.ContainsKey(assetName)) { bundle.TexturePaths.Add(t, new SafenedFilename(RevitTextures[assetName])); } else { //Logger.LogError( // $"Found asset outisde of Revit material lib: {path.Value}. Could not add to export" // ); } } } // Return the bundle we created. bundles.Add(bundle); } catch (Exception e) { //Logger.LogException("Error in bundle creation: ", e); } } var bundleList = bundles.Where(b => b != null).ToList(); _bundleCache.Add(doc.PathName, bundleList); paths = _texturePathCache[doc.PathName]; return(bundleList); }
public static Assimp.Material ConvertToAssimpMaterial(TextureBundle bundle, Document doc) { // Create new material with base props // from the Revit material var newmat = new Assimp.Material() { Opacity = bundle.Material.GetOpacity(), Reflectivity = 0f, Name = bundle.Material.Name, ColorDiffuse = bundle.Material.ToColor4D() }; // Extract base properties from revit material ElementId appearanceAssetId = bundle.Material.AppearanceAssetId; AppearanceAssetElement appearanceAsset = doc.GetElement(appearanceAssetId) as AppearanceAssetElement; Asset renderingAsset = appearanceAsset.GetRenderingAsset(); RenderAppearanceDescriptor rad = new RenderAppearanceDescriptor(renderingAsset); PropertyDescriptorCollection collection = rad.GetProperties(); List <PropertyDescriptor> orderableCollection = new List <PropertyDescriptor>(collection.Count); List <string> allPropNames = orderableCollection.Select(f => f.Name).ToList(); foreach (PropertyDescriptor descr in collection) { orderableCollection.Add(descr); switch (descr.Name) { #region Notes // The commented out properties aren't in use yet, // but do work with revit materials as expected. //case "texture_UScale": // var uScale = renderingAsset["texture_UScale"] as AssetPropertyDouble; // break; //case "texture_VScale": // break; //case "texture_UOffset": // break; //case "texture_VOffset": // break; //case "texture_RealWorldScaleX": // var xScale = renderingAsset["texture_RealWorldScaleX"] as AssetPropertyDistance; // break; //case "texture_RealWorldScaleY": // break; #endregion case "generic_diffuse": var prop = renderingAsset.GetAssetProperty <AssetPropertyDoubleArray4d>("generic_diffuse"); newmat.ColorDiffuse = ColorFromAssetDoubleArray4d(prop); break; case "glazing_reflectance": // This is glass, so we should reduce the transparency. var refl = renderingAsset.GetAssetProperty <AssetPropertyDouble>("glazing_reflectance"); if (refl == null) { var reflFloat = renderingAsset.GetAssetProperty <AssetPropertyFloat>("glazing_reflectance"); newmat.Reflectivity = reflFloat?.Value ?? 0f; } else { newmat.Reflectivity = (float)refl.Value; } newmat.Opacity = Math.Abs(0f - newmat.Reflectivity); break; case "common_Tint_color": // Tint shouldn't be used if generic diffuse is set if ( renderingAsset.GetAssetProperty <AssetPropertyDoubleArray4d>("generic_diffuse") != null ) { continue; } var tintProp = renderingAsset.GetAssetProperty <AssetPropertyDoubleArray4d>("common_Tint_color"); newmat.ColorDiffuse = ColorFromAssetDoubleArray4d(tintProp); break; default: break; } } // Set textures foreach (var tx in bundle.TexturePaths) { // Get the filename var txFileName = tx.Value.SafeFileName; if (tx.Key == RevitTextureType.Color) { newmat.TextureDiffuse = new TextureSlot( $"Textures/{txFileName}", TextureType.Diffuse, 0, // Texture index in the material TextureMapping.Box, 0, // 0.5f, // Blend mode TextureOperation.Add, TextureWrapMode.Clamp, TextureWrapMode.Clamp, 0 // Flags, ); } else if (tx.Key == RevitTextureType.Bump) { newmat.TextureHeight = new TextureSlot( $"Textures/{txFileName}", TextureType.Diffuse, 0, // Texture index in the material TextureMapping.Box, 0, // 0.5f, // Blend mode TextureOperation.Add, TextureWrapMode.Clamp, TextureWrapMode.Clamp, 0 // Flags, ); } } return(newmat); }