Creating Textured Materials using Helper Classes for Assets in Teigha BIM

Evgeniy Tikhonov

October 13, 2017

Teigha BIM supports fourteen default materials: Ceramic, Concrete, Generic, Glazing, Hardwood, MasonryCMU, Metal, MetallicPaint, Mirror, PlasticVinyl, SolidGlass, Stone, WallPaint and Water. Each material has a rendering asset, which contains material rendering properties, such as color, finishing style, bumping and so on. Textures can also be defined for a material.

Almost all default materials support textures — textures are not only for Metal, Mirror and Water materials. A texture can be used as a ‘skin’ of an element, and it’s also possible to define finishing effects for the material using bitmap files. To access or set up textures of a material, the appropriate properties should be used. For example, a texture can be set for the Stone material in the ‘stone_color’ property, but also the Stone material has ‘stone_pattern_map’ which defines a finishing style of the material.

Teigha BIM provides the OdBmAppearanceAssetHelper class to create built-in materials and to access material properties. A default texture can be set for a material in a helper class constructor. Other textures are accessible through material properties. To get, set or modify data of a material texture, the helper class OdBmUnifiedBitmapSchemaHelper can be used.

Example of creating a new generic material with a texture:

OdBmMaterialElemPtr pMaterialElem = OdBmMaterialElem::createObject();
OdBmMaterialTrackingPtr pMaterialTrackingMgr = pDb->getAppInfo(OdBm::ManagerType::MaterialTracking);
OdBmObjectId matObjId = pMaterialTrackingMgr->addMaterial(L"Textured_Material", pMaterialElem);
pMaterialElem->setDatabaseDefaults(pDb);

OdBmAppearanceAssetElemPtr pAppAsset = OdBmAppearanceAssetElem::createObject();
OdBmAppearanceAssetHelper appAssetHelper = OdBmAppearanceAssetHelper(pDb, pMaterialElem->getName(), pAppAsset, OdBm::PredefinedAppearanceAsset::kGeneric, L"texture.png");
OdBmMaterialPtr pMaterial = pMaterialElem->getMaterial();
appAssetHelper.applyToMaterial(pMaterial);

// set properties of material texture
OdBmAssetPtr textureAsset;
OdTf::ErrorStatus es = appAssetHelper.getTextureAsset(textureAsset);
OdBmUnifiedBitmapSchemaHelper textureHelper(textureAsset);

textureHelper.setLinkTextureTransforms(true);
textureHelper.setOffsetLock(true);
textureHelper.setRealWorldOffset(OdGePoint2d(50., 50.), OdBm::kDUT_DECIMAL_INCHES);
textureHelper.setRealWorldScale(OdGePoint2d(50., 50.), OdBm::kDUT_DECIMAL_INCHES);
textureHelper.setScaleLock(false);
textureHelper.setUVRepeat(true, true);
textureHelper.setWAngle(OdaPI4);
textureHelper.setBlur(1.5);
textureHelper.setFiltering(1);
textureHelper.setInvert(false);

Example of accessing the texture of an existing material in a database.

OdBmDatabasePtr pDbDst = app->readFile(L"myMaterial_tmp.rvt", true);
OdBmMaterialElemPtr pMaterialElem = pDbDst->getObjectId(0xFEEE).safeOpenObject();

OdBmAppearanceAssetElemPtr pAppearanceAssetElem = pMaterialElem->getMaterial()->getAppearanceAssetId().safeOpenObject();
OdBmAppearanceAssetHelper appAssetHelper = OdBmAppearanceAssetHelper(pAppearanceAssetElem);
// set properties of default (in diffuse channel) material texture
OdBmAssetPtr textureAsset;
OdTf::ErrorStatus es = appAssetHelper.getTextureAsset(textureAsset);
OdBmUnifiedBitmapSchemaHelper textureHelper(textureAsset);

Example of accessing the texture of an existing material in a database. Some additional functions are used.

static OdString getSchemaName(const OdBmAsset* pAsset) 
{
  OdString schemaName;
  if (pAsset->getAPropertyString(ASSET_PROP_UIDEFINITION, schemaName) == OdTf::eOk) 
  {
    schemaName.replace(L"\\", L"/");
    OdInt32 nSlashPos = schemaName.reverseFind(L"/")+1;
    schemaName = schemaName.mid(nSlashPos, schemaName.find(L"UI.xml")-nSlashPos);
  }
  else 
    schemaName = pAsset->getName().left(pAsset->getName().find(L"Schema"));

  return schemaName;
}

Main code:

OdBmDatabasePtr pDbDst = app->readFile(L"Stone.rfa", true);
OdBmMaterialElemPtr pMaterialElem = pDbDst->getObjectId(0xFEEE).safeOpenObject();
OdBmAssetPtr pAsset = pMaterialElem ->getMaterial()->getAsset();
OdBmAPropertyPtr pProperty;
if (pAsset->getAProperty(L”stone_pattern_map”, pProperty) && !pProperty.isNull()) 
{
  OdBmObjectPtrArray connAssets;
  pProperty->getAConnected(connAssets);
  for(OdBmObjectPtrArray::const_iterator it = connAssets.begin(); it != connAssets.end(); it++) 
  {
    OdBmAssetPtr pBitmapAsset = *it;
    OdString schemaName = ::getSchemaName(pBitmapAsset);
    if (schemaName.iCompare(L"UnifiedBitmap") != 0)
      continue;

    OdBmUnifiedBitmapSchemaHelper helper(pBitmapAsset);
    // work with texture mapping
    break;    
  }
}