Revit2020材质自定义导出如何设置UV坐标

使用IExportContext接口实现自定义导出的时候,发现通过(PolymeshTopology)node.GetUVs()得到的UV坐标和纹理图不匹配,这导致的结果是导出的纹理被缩放,如下图

[图片]revit中的屋顶纹理

[图片]导出的b3dm屋顶纹理

经过一番排查,发现revit在设置材质贴图的时候会设置贴图的实际长宽尺寸,对应材质属性中的texture_RealWorldScaleX和texture_RealWorldScaleY

[图片]纹理编辑器页面

我们可以利用这两个参数重新计算UV值

1、首先需要获得这两个属性的值

[代码]获取texture_RealWorldScaleX和texture_RealWorldScaleY
Autodesk.Revit.DB.Visual.Asset currentAsset = null;

public void OnMaterial(MaterialNode node)
{
  //获取Asset
  if (node.HasOverriddenAppearance)
  {
      currentAsset = node.GetAppearanceOverride();
  }
  else
  {
      currentAsset = node.GetAppearance();
  }
  //关键代码
  try
  {
      Asset textureAsset = FindTextureAsset(asset as AssetProperty);
      //获取实际缩放尺寸X
      {
          string name = "texture_RealWorldScaleX";
          AssetProperty property = textureAsset.FindByName(name);
          var propertyTyped = property as AssetPropertyDistance;
          //转换为公制单位
          TextureRealWorldScaleX = 
              UnitUtils.Convert(propertyTyped.Value, 
              propertyTyped.DisplayUnitType, DisplayUnitType.DUT_METERS);
          
      }
      //获取实际缩放尺寸Y
      {
          string name = "texture_RealWorldScaleY";
          AssetProperty property = textureAsset.FindByName(name);
          var propertyTyped = property as AssetPropertyDistance;
          //转换为公制单位
          TextureRealWorldScaleY = 
              UnitUtils.Convert(propertyTyped.Value,
              propertyTyped.DisplayUnitType, DisplayUnitType.DUT_METERS);
      }
  }
  catch (Exception e)
  {
      
  }
}


[代码]FindTextureAsset自定义方法,用递归找到包含贴图信息的Asset
        private Autodesk.Revit.DB.Visual.Asset FindTextureAsset(AssetProperty ap)
        {
            //Log("--FindTextureAsset--");
            Autodesk.Revit.DB.Visual.Asset result = null;
            if (ap.Type == AssetPropertyType.Asset)
            {
                if (!IsTextureAsset(ap as Autodesk.Revit.DB.Visual.Asset))
                {
                    for (int i = 0; i < (ap as Autodesk.Revit.DB.Visual.Asset).Size; i++)
                    {
                        if (null != FindTextureAsset((ap as Autodesk.Revit.DB.Visual.Asset)[i]))
                        {
                            result = FindTextureAsset((ap as Autodesk.Revit.DB.Visual.Asset)[i]);
                            break;
                        }
                    }
                }
                else
                {
                    result = ap as Autodesk.Revit.DB.Visual.Asset;
                }
                //Log("--FindTextureAsset-end-");
                return result;
            }
            else
            {
                for (int j = 0; j < ap.NumberOfConnectedProperties; j++)
                {
                    if (null != FindTextureAsset(ap.GetConnectedProperty(j)))
                    {
                        result = FindTextureAsset(ap.GetConnectedProperty(j));
                    }
                }
                //Log("--FindTextureAsset-end-");
                return result;
            }
        }

[代码]IsTextureAsset自定义方法,判断Asset是否包含贴图信息
        private bool IsTextureAsset(Autodesk.Revit.DB.Visual.Asset asset)
        {
            AssetProperty assetProprty = GetAssetProprty(asset, "assettype");
            if (assetProprty != null && (assetProprty as AssetPropertyString).Value == "texture")
            {
                return true;
            }
            return GetAssetProprty(asset, "unifiedbitmap_Bitmap") != null;
        }

2、接下来计算UV值

[代码]计算UV值
//取得UV坐标
IList<UV> uvs = node.GetUVs();
//重新计算UV值        
foreach (UV uv in uvs)
{
    double u = UnitUtils.ConvertFromInternalUnits(uv.U, DisplayUnitType.DUT_METERS);
    double v = UnitUtils.ConvertFromInternalUnits(uv.V, DisplayUnitType.DUT_METERS);
    baseTexCoords.Add(u / currentMaterial.TextureRealWorldScaleX);
    baseTexCoords.Add(v / currentMaterial.TextureRealWorldScaleY);

}

这样就能得到和revit中相同的纹理显示效果
参考文章
Revit API: IExportContext converting UV to the range (0,1) - Revit API Forum

参考思路

posted @ 2022-06-24 09:54  ARL  阅读(844)  评论(0)    收藏  举报