在 Autodesk Revit Forge Design Automation 中创建带纹理的 material
Creating a material with texture in Autodesk Revit Forge Design Automation
我目前正在处理 Autodesk Forge Design Automation 云解决方案 中 运行 的一些 Revit API 代码。基本上,我正在尝试 创建一个 material 并通过以下代码向其附加纹理 :
private void AddTexturePath(AssetProperty asset, string texturePath) {
Asset connectedAsset = null;
if (asset.NumberOfConnectedProperties == 0)
asset.AddConnectedAsset("UnifiedBitmapSchema");
connectedAsset = (Asset) asset.GetConnectedProperty(0);
AssetPropertyString path = (AssetPropertyString) connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
if (!path.IsValidValue(texturePath)) {
File.Create("texture.png");
texturePath = Path.GetFullPath("texture.png");
}
path.Value = texturePath;
}
这实际上工作得很好,因为纹理路径的值:
path.Value = texturePath;
需要引用现有文件。我在Forge的云实例上没有这个文件,因为纹理名称的路径是用户在发送Workitem请求时指定的。
问题是这会将 material 的纹理路径设置为如下所示:
T:\Aces\Jobs\<workitem_id>\texture.png
这基本上是 Workitem 实例的工作文件夹。这个路径是没有用的,因为像这样的纹理路径的 material 需要在 Revit 中手动重新链接。
如果我能以某种方式将 material 纹理路径映射到一些用户友好的目录,如 "C:\Textures\texture.png" 并且 Forge 实例似乎有一个 "C:\" 驱动器存在(可能是某种 Windows 实例),但我的代码运行在低权限下,因此它无法在工作目录之外创建任何类型的 directories/files。
有人知道如何解决这个问题吗?任何帮助将不胜感激!
经过一整天的研究,我几乎得出了一个令人满意的解决方案。为清楚起见 - 我将参考 Autodesk Forge Design Automation API for Revit,简称为 "Forge".
基本上上面提供的代码是正确的。我没有找到在 Forge 实例上创建文件的任何可能方法,该文件位于不同于 Workitem 工作目录的目录中:
T:\Aces\Jobs\<workitem_id>\texture.png
有趣的是,Forge 实例上有一个 C:\ 驱动器,其中包含 Windows、Revit 和 .NET Framework 安装(因为 Forge 实例基本上是某种带有 Revit 的 Windows 实例安装)。可以枚举很多这样的目录,但是 none 我已经尝试过(而且我已经尝试了很多 - 大多数是最明显的,public 访问 Windows 目录例如 C:\Users\Public、C:\Program Files 等)允许创建目录或文件。这对应于 Forge 文档的“限制”区域中的说明:
Your application is run with low privileges, and will not be able to freely interact with the Windows OS :
- Write access is typically restricted to the job’s working folder.
- Registry access is mostly restricted, writing to the registry should be avoided.
- Any sub-process will also be executed with low privileges.
因此,在尝试将“虚拟”纹理文件保存在 Forge C:\ 驱动器的某处后,我找到了另一个解决方案 - 纹理的纹理路径实际上无关紧要。
这是因为 Revit 提供了重新 link 纹理的替代方法。如果启动 Revit,您可以转到文件 -> 选项 -> 渲染,然后在“其他渲染外观路径”字段下,您可以指定本地计算机上的目录,Revit 可以使用该目录查找丢失的纹理。有了这些,您可以执行以下操作以完全控制在 Forge 上创建 materials:
- 将 Workitem 发送到 Forge,创建 materials。
- 在工作目录中使用正确的文件名创建虚拟纹理。
- 将虚拟纹理文件附加到 material。
- 输出生成的文件(.rvt 或 .rfa,取决于您在 Forge 上创建的内容)。
- 将所有纹理放入一个文件夹(或多个,这无关紧要)。
- 将带有纹理的目录添加到附加渲染外观路径。
- Revit 将成功地将所有纹理重新link到新路径。
我希望有人会觉得这有用!
此外,根据 Jeremy 的要求,我 post 一个代码示例,用于使用 Revit API(在 C# 中)创建带有纹理的 material 和修改 Revit 中不同的外观属性:
private void SetAppearanceParameters(Document project, Material mat, MaterialData data) {
using(Transaction setParameters = new Transaction(project, "Set material parameters")) {
setParameters.Start();
AppearanceAssetElement genericAsset = new FilteredElementCollector(project)
.OfClass(typeof(AppearanceAssetElement))
.ToElements()
.Cast < AppearanceAssetElement > ().Where(i = >i.Name.Contains("Generic"))
.FirstOrDefault();
AppearanceAssetElement newAsset = genericAsset.Duplicate(data.Name);
mat.AppearanceAssetId = newAsset.Id;
using(AppearanceAssetEditScope editAsset = new AppearanceAssetEditScope(project)) {
Asset editableAsset = editAsset.Start(newAsset.Id);
AssetProperty assetProperty = editableAsset["generic_diffuse"];
SetColor(editableAsset, data.MaterialAppearance.Color);
SetGlossiness(editableAsset, data.MaterialAppearance.Gloss);
SetReflectivity(editableAsset, data.MaterialAppearance.Reflectivity);
SetTransparency(editableAsset, data.MaterialAppearance.Transparency);
if (data.MaterialAppearance.Texture != null && data.MaterialAppearance.Texture.Length != 0)
AddTexturePath(assetProperty, $@"C:\{data.MaterialIdentity.Manufacturer}\textures\{data.MaterialAppearance.Texture}");
editAsset.Commit(true);
}
setParameters.Commit();
}
}
private void SetTransparency(Asset editableAsset, int transparency) {
AssetPropertyDouble genericTransparency = editableAsset["generic_transparency"] as AssetPropertyDouble;
genericTransparency.Value = Convert.ToDouble(transparency);
}
private void SetReflectivity(Asset editableAsset, int reflectivity) {
AssetPropertyDouble genericReflectivityZero = (AssetPropertyDouble) editableAsset["generic_reflectivity_at_0deg"];
genericReflectivityZero.Value = Convert.ToDouble(reflectivity) / 100;
AssetPropertyDouble genericReflectivityAngle = (AssetPropertyDouble) editableAsset["generic_reflectivity_at_90deg"];
genericReflectivityAngle.Value = Convert.ToDouble(reflectivity) / 100;
}
private void SetGlossiness(Asset editableAsset, int gloss) {
AssetPropertyDouble glossProperty = (AssetPropertyDouble) editableAsset["generic_glossiness"];
glossProperty.Value = Convert.ToDouble(gloss) / 100;
}
private void SetColor(Asset editableAsset, int[] color) {
AssetPropertyDoubleArray4d genericDiffuseColor = (AssetPropertyDoubleArray4d) editableAsset["generic_diffuse"];
Color newColor = new Color((byte) color[0], (byte) color[1], (byte) color[2]);
genericDiffuseColor.SetValueAsColor(newColor);
}
private void AddTexturePath(AssetProperty asset, string texturePath) {
Asset connectedAsset = null;
if (asset.NumberOfConnectedProperties == 0) asset.AddConnectedAsset("UnifiedBitmapSchema");
connectedAsset = (Asset) asset.GetConnectedProperty(0);
AssetProperty prop = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
AssetPropertyString path = (AssetPropertyString) connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
string fileName = Path.GetFileName(texturePath);
File.Create(fileName);
texturePath = Path.GetFullPath(fileName);
path.Value = texturePath;
}
我目前正在处理 Autodesk Forge Design Automation 云解决方案 中 运行 的一些 Revit API 代码。基本上,我正在尝试 创建一个 material 并通过以下代码向其附加纹理 :
private void AddTexturePath(AssetProperty asset, string texturePath) {
Asset connectedAsset = null;
if (asset.NumberOfConnectedProperties == 0)
asset.AddConnectedAsset("UnifiedBitmapSchema");
connectedAsset = (Asset) asset.GetConnectedProperty(0);
AssetPropertyString path = (AssetPropertyString) connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
if (!path.IsValidValue(texturePath)) {
File.Create("texture.png");
texturePath = Path.GetFullPath("texture.png");
}
path.Value = texturePath;
}
这实际上工作得很好,因为纹理路径的值:
path.Value = texturePath;
需要引用现有文件。我在Forge的云实例上没有这个文件,因为纹理名称的路径是用户在发送Workitem请求时指定的。
问题是这会将 material 的纹理路径设置为如下所示:
T:\Aces\Jobs\<workitem_id>\texture.png
这基本上是 Workitem 实例的工作文件夹。这个路径是没有用的,因为像这样的纹理路径的 material 需要在 Revit 中手动重新链接。
如果我能以某种方式将 material 纹理路径映射到一些用户友好的目录,如 "C:\Textures\texture.png" 并且 Forge 实例似乎有一个 "C:\" 驱动器存在(可能是某种 Windows 实例),但我的代码运行在低权限下,因此它无法在工作目录之外创建任何类型的 directories/files。
有人知道如何解决这个问题吗?任何帮助将不胜感激!
经过一整天的研究,我几乎得出了一个令人满意的解决方案。为清楚起见 - 我将参考 Autodesk Forge Design Automation API for Revit,简称为 "Forge".
基本上上面提供的代码是正确的。我没有找到在 Forge 实例上创建文件的任何可能方法,该文件位于不同于 Workitem 工作目录的目录中:
T:\Aces\Jobs\<workitem_id>\texture.png
有趣的是,Forge 实例上有一个 C:\ 驱动器,其中包含 Windows、Revit 和 .NET Framework 安装(因为 Forge 实例基本上是某种带有 Revit 的 Windows 实例安装)。可以枚举很多这样的目录,但是 none 我已经尝试过(而且我已经尝试了很多 - 大多数是最明显的,public 访问 Windows 目录例如 C:\Users\Public、C:\Program Files 等)允许创建目录或文件。这对应于 Forge 文档的“限制”区域中的说明:
Your application is run with low privileges, and will not be able to freely interact with the Windows OS :
- Write access is typically restricted to the job’s working folder.
- Registry access is mostly restricted, writing to the registry should be avoided.
- Any sub-process will also be executed with low privileges.
因此,在尝试将“虚拟”纹理文件保存在 Forge C:\ 驱动器的某处后,我找到了另一个解决方案 - 纹理的纹理路径实际上无关紧要。 这是因为 Revit 提供了重新 link 纹理的替代方法。如果启动 Revit,您可以转到文件 -> 选项 -> 渲染,然后在“其他渲染外观路径”字段下,您可以指定本地计算机上的目录,Revit 可以使用该目录查找丢失的纹理。有了这些,您可以执行以下操作以完全控制在 Forge 上创建 materials:
- 将 Workitem 发送到 Forge,创建 materials。
- 在工作目录中使用正确的文件名创建虚拟纹理。
- 将虚拟纹理文件附加到 material。
- 输出生成的文件(.rvt 或 .rfa,取决于您在 Forge 上创建的内容)。
- 将所有纹理放入一个文件夹(或多个,这无关紧要)。
- 将带有纹理的目录添加到附加渲染外观路径。
- Revit 将成功地将所有纹理重新link到新路径。
我希望有人会觉得这有用!
此外,根据 Jeremy 的要求,我 post 一个代码示例,用于使用 Revit API(在 C# 中)创建带有纹理的 material 和修改 Revit 中不同的外观属性:
private void SetAppearanceParameters(Document project, Material mat, MaterialData data) {
using(Transaction setParameters = new Transaction(project, "Set material parameters")) {
setParameters.Start();
AppearanceAssetElement genericAsset = new FilteredElementCollector(project)
.OfClass(typeof(AppearanceAssetElement))
.ToElements()
.Cast < AppearanceAssetElement > ().Where(i = >i.Name.Contains("Generic"))
.FirstOrDefault();
AppearanceAssetElement newAsset = genericAsset.Duplicate(data.Name);
mat.AppearanceAssetId = newAsset.Id;
using(AppearanceAssetEditScope editAsset = new AppearanceAssetEditScope(project)) {
Asset editableAsset = editAsset.Start(newAsset.Id);
AssetProperty assetProperty = editableAsset["generic_diffuse"];
SetColor(editableAsset, data.MaterialAppearance.Color);
SetGlossiness(editableAsset, data.MaterialAppearance.Gloss);
SetReflectivity(editableAsset, data.MaterialAppearance.Reflectivity);
SetTransparency(editableAsset, data.MaterialAppearance.Transparency);
if (data.MaterialAppearance.Texture != null && data.MaterialAppearance.Texture.Length != 0)
AddTexturePath(assetProperty, $@"C:\{data.MaterialIdentity.Manufacturer}\textures\{data.MaterialAppearance.Texture}");
editAsset.Commit(true);
}
setParameters.Commit();
}
}
private void SetTransparency(Asset editableAsset, int transparency) {
AssetPropertyDouble genericTransparency = editableAsset["generic_transparency"] as AssetPropertyDouble;
genericTransparency.Value = Convert.ToDouble(transparency);
}
private void SetReflectivity(Asset editableAsset, int reflectivity) {
AssetPropertyDouble genericReflectivityZero = (AssetPropertyDouble) editableAsset["generic_reflectivity_at_0deg"];
genericReflectivityZero.Value = Convert.ToDouble(reflectivity) / 100;
AssetPropertyDouble genericReflectivityAngle = (AssetPropertyDouble) editableAsset["generic_reflectivity_at_90deg"];
genericReflectivityAngle.Value = Convert.ToDouble(reflectivity) / 100;
}
private void SetGlossiness(Asset editableAsset, int gloss) {
AssetPropertyDouble glossProperty = (AssetPropertyDouble) editableAsset["generic_glossiness"];
glossProperty.Value = Convert.ToDouble(gloss) / 100;
}
private void SetColor(Asset editableAsset, int[] color) {
AssetPropertyDoubleArray4d genericDiffuseColor = (AssetPropertyDoubleArray4d) editableAsset["generic_diffuse"];
Color newColor = new Color((byte) color[0], (byte) color[1], (byte) color[2]);
genericDiffuseColor.SetValueAsColor(newColor);
}
private void AddTexturePath(AssetProperty asset, string texturePath) {
Asset connectedAsset = null;
if (asset.NumberOfConnectedProperties == 0) asset.AddConnectedAsset("UnifiedBitmapSchema");
connectedAsset = (Asset) asset.GetConnectedProperty(0);
AssetProperty prop = connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
AssetPropertyString path = (AssetPropertyString) connectedAsset.FindByName(UnifiedBitmap.UnifiedbitmapBitmap);
string fileName = Path.GetFileName(texturePath);
File.Create(fileName);
texturePath = Path.GetFullPath(fileName);
path.Value = texturePath;
}