OBJ 是一种由 Wavefront 开发的文件格式,常用于存储 3D 模型几何定义。它主要用作不同 3D 应用程序之间的交换格式,并已成为模型互操作性的事实标准之一。许多 3D 模型库都提供以这种中立格式下载其模型的选项。
存储在 .obj 文件中的模型可以通过 .mtl 文件中详细的材质规范进行丰富,这些 .mtl 文件从 .obj 文件中引用,因此导出的模型在转换为 OBJ 后不会丢失其视图。材质被分配给面,并且 .mtl 文件始终与 .obj 文件分离,因此一个 .mtl 文件可以被许多 .obj 文件引用。或者,如果不需要材质,可以简单地删除 .mtl 文件。使用 Teigha 导入 .obj 文件的能力还使用户能够访问来自流行的基于网络的 3D 模型库(或制造商的封闭库)的整套模型,这些模型可以快速用作其图纸中的附加/装饰设计元素,例如。
OBJ 是一种开放的文本格式,文件结构并非固定不变。在网络上可以找到多种 .obj 变体甚至方言。Teigha 在读取和解析文件时,会尝试支持所有发现的与通用规范的偏差。
在 Teigha 应用程序中使用模块
OBJ 导入/导出功能在 OBJToolkit 项目中实现,该项目是 Components 库的一部分,位于 Components/OBJToolkit 目录中。项目解决方案中的路径相同。Teigha 用户可以使用一个头文件 OBJToolkit.h;它包含所有接口、变量和定义,以便开始使用 .obj 和 .mtl 文件。默认的 .tx 模块名称 OdObjToolkitModuleName (“OBJToolkit.tx”) 在 Kernel\Include\OdModuleNames.h 头文件中定义,通过包含此头文件即可使用。但是,模块的加载可以通过调用 loadObjToolkitModule() 函数来执行,该函数也实现在 OBJToolkit.h 中。以下是在您的应用程序中开始支持 .obj 的最快方法:
OdObjToolkitModulePtr module = loadObjToolkitModule();
主模块导出的 OdObjToolkitModule 类有几种方法:
- OdObjImportPtr createObjImporter() — 创建一个对象,该对象是 OdObjDb 结构中 .obj 文件加载器的实现(保留导入的几何数据)以及相关的 OdMtlDb(存储与导入的 .obj 文件关联的材质定义)。
- OdObjExportPtr createObjExporter() — 创建一个对象,该对象可以将指定的 OdObjDb 结构保存到 .obj 文件中。
- OdMtlImportPtr createMtlImporter() — 返回一个指向已创建对象的指针,该对象可以将包含材质信息的 .mtl 文件加载到 OdMtlDb 中。
- OdMtlExportPtr createMtlExporter() — 创建并返回一个指向对象的指针,该对象将指定的 OdMtlDb 导出到 .mtl 文件中。
- OdResult exportObj(OdDbBaseDatabase *pDb, const OdGiDrawable *pEntity, const OdString &fileName, OdObjExportOptions *options = NULL) — 将定义的 OdGiDrawable 对象导出到 .obj 文件中。此方法用于 ExCustObjs 示例命令“OBJExport”,该命令可在加载 ExCustObjs.tx 模块(Drawings/Examples)后从 OdaMfcApp 调用。
- OdResult exportObj(OdDbBaseDatabase *pDb, const OdString &fileName, OdObjExportOptions *options = NULL) — 将定义的视图导出到 .obj 文件中。此方法也用于从 Teigha Visualize Viewer 导出视图。
一旦 .obj 文件导入到 OdObjDb 中,可以使用以下结构访问导入的实体:
- 分组通过 .obj 语法中的标签“g”(组)执行。每个组可以包含点集、多段线、曲线(目前仅支持 B 样条曲线)和面等对象。例如,点集可用于定义点云。
- 从 OBJ 格式的角度来看,每个面都是一个独立的实体,因此用户可以使用 OdObjEntityIterator 分别访问每个面,该迭代器在 skipFace 参数等于 false 时创建。
在 OdObjDb 类的 getGroupShell 方法中也实现了将组的所有面收集到单个壳中以获得复杂网格模型的功能。
简而言之,Teigha 中 .obj 文件对象模型的层次结构可以描述如下:
- OdObjDb 维护一组命名组。
- 每个组包含多个对象(点集、多段线、曲线、面)。
- 可以使用 OdObjDb 的 getGroupShell 方法从组的所有面创建一个单独的壳。
以下是导入 .obj 文件并遍历所有导入的组及其实体的示例代码(类似代码可在 Components/Visualize/Examples/Obj2Visualize 项目中找到):
OdObjImportPtr pObjImporter = OBJToolkit::createObjImporter();
OdResult res = pObjImporter->importFile(filePath);
OdObjDbPtr pObjDb = pObjImporter->getObjDb();
OdString modelName = pObjImporter->getDrawingName();
OdObjGroupIteratorPtr itGroups = pObjDb->createGroupsIterator();
while (itGroups->done() == false)
{
OdObjGroupPtr pGroup = itGroups->element();
if (pGroup.isNull() == false && pGroup->isEmpty() == false)
{
if (eOk == pObjDb->getGroupShell(pGroup, vertices, texCoo, normals, faces, faceMtls) && faces.size() > 0)
{
// process shell data
}
// and walking through all other entities in the group
OdObjEntityIteratorPtr it = pGroup->createEntitiesIterator();
while (it->done() == false)
{
const OdObjGeomEntity *pEntity = it->element();
const eOBJEntType entType = pEntity->type();
switch (entType)
{
case eOBJEntPoints:
{
if (!pEntity->m_vind.isEmpty())
{
// process set of points
}
}
break;
case eOBJEntLine:
{
if (!pEntity->m_vind.isEmpty())
{
// process polyline
}
}
break;
case eOBJEntCurve:
{
// process curve
}
break;
}
it->step();
}
}
itGroups->step();
}
使用OBJ一切都非常简单!