本人对于 BIM 一无所知,笔记中都是搜索引擎查找+猜测+总结的成果,一些结论和断言会有不准确和不专业之处,请多多见谅。
工作的项目中需要在页面中展示 BIM。
BIM 有很多解释,这里指的是 Building Information Model - 建筑信息模型,简单说就是为建筑工程绘制的 2D/3D 模型。
功能需求是:将提供的 .rvt 文件的模型展示在 web 页面中。
经过一番研究:
.rvt 格式是 Autodesk Revit 开发的项目文件。.rvt 文件,three.js 可以通过加载 .rvt 文件转化的 .json 文件展示模型内容。.rvt 转化成 .json(实际上是一堆 .json 和其他资源文件),要用 revit 软件,例如,付费软件 Autodesk Revit,试用版 16GB….rvt 测试文件不好找,转换完的 .json 文件也不好找,本人没找到,测试用的文件是客户给的,所以不方便提供。Autodesk Forge 官方提供了一些示例文件,不过我没下载成功,你可以试试: Revit 示例项目文件Autodesk Forge 提供了很多 API 用于开发和管理模型数据,还可以使用 Autodesk Forge Viewer 在页面上加载展示模型。
Autodesk Forge 的工作人员提供了一个 《Autodesk Forge中文帮助中心》,里面包括教程文档、Forge 进阶、常见问题、在线工具等很多内容,阅读它们是最快掌握 Forge 的途径,建议至少阅读完 《Autodesk Forge 学习简谈系列》。
系列中有称为 learnforge 的新手案例教程,包括视频教程《Forge Viewer案例从搭建到部署》和视频中的《参考文档》,具体的搭建和演示本人就不重复了,建议自己搭一遍,熟悉简单的流程。
我跟着 Nodejs 案例搭建了一遍,一直到成功展示到页面,至此我的需求就基本满足了,所以就没有继续看后面的扩展。
案例的大致流程是:
官方注册账号并登录,开启试用
创建 App,主要用来获取开发用的 Client ID 和 Client Secret,基于它们生成具体访问指定范围权限的 token,调用 API 时需将 token 传递过去。
Forge 将数据存储在云端的名叫 bucket 的容器(抽象)中。
.rvtForge 可以任意支持的模型文件转化成 SVF 格式(.svf ),.svf 文件记录了模型中使用到了哪些资源,通过它可以得知需要加载哪些文件,包括 .json、图片、.gz、.bin 等。
案例中通过 Viewer 加载远程的 svf 文件进而加载相关资源文件,最终渲染整个模型。
SVF 不是单一文件,是一个数据包,包括了构建集合信息,属性包,有一个 .svf 的清单文件(二维模型时.f2d)。而 Forge Viewer 的 JavaScript 库对此数据进行解析和渲染。 目前 SVF 数据格式并没有文档说明,也无官方端口直接下载数据包。不过可以按清单文件下载到这些文件。 注意:SVF2 暂时还不支持下载数据包。
Forge Viewer 支持 SVF 格式是内部格式,作为入口的 .svf 文件实际上就是个压缩包,可以通过压缩软件解压。其中包含的 manifest.json 文件记录了模型所需的相关资源的文件地址,例如 .json、图片、.gz、.bin 等。
下图是 {3D}.svf 文件解压结果:

通过搭建案例已经实现基本的展示需求,但实际上,转化的数据都存储在 Forge 云端 服务器 ,这样对于数据管理和网络请求都是不友好的,所以还需要将其下载到自己的私有服务器进行存储。
可是 Forge 并没有提供傻瓜式的一键下载 SVF 包的功能。
好在官方开发人员提出了可行的方案,就是根据获取到的文件清单,批量进行手动下载打包,见《Autodesk Forge 学习简谈 - 4》。
团队中也有人(PHILIPPE LEEFSMA)从已废弃的官方在线工具中解耦了 “下载离线 SVF 包” 的功能:《Forge SVF Extractor in Node.js》
官方还开发了支持一键下载的 vscode 插件,也可以参考源码开发自己的下载功能。
.svf 文件和其记录的相关资源统称为 SVF,Forge 称呼这些转化后的结果为 Derivatives - SVF 衍生(或派生)文件。
通过 DerivativesApi 和 URN 可以提取模型的 manifest 数据,其中存储了这个模型的 Derivatives 信息,再通过 Derivatives 信息中的路径手动拼接官方地址就是 Viewer 加载的文件地址。
将这些衍生文件的路径全部整合好,进行批量下载并存储到本地就实现了 SVF 包的下载。
URN:Uniform Resource Name(统一资源名称)不同与 URL(统一资源定位符)的标准格式的URI,以唯一名称的方式指向资源,而不是资源的所在地。更多请参考《HTTP 权威指南》中 URN 的介绍。
本人使用的 PHILIPPE 的解耦代码,并对代码进行了一些调整以使其可以直接使用:
最终结果:
// ExtractorSvc.js
const archiver = require('archiver')
const {
DerivativesApi } = require('forge-apis')
const request = require('request')
const mkdirp = require('mkdirp')
const Zip = require('node-zip')
const Zlib = require('zlib')
const path = require('path')
const fs = require('fs')
const _ = require('lodash')
// 转化路径中的分隔符
// path 会将路径中的路径分隔符全部转化为当前环境的默认格式,可能会是 `\`,在拼接其它路径时可能会有问题,这里进行了统一替换
function formatSep(str, sep = path.sep) {
const reg = new RegExp(sep === '/' ? '\\\\' : '/', 'g')
return str.replace(reg, sep)
}
// Extractor Service 类
class ExtractorSvc {
// 构造函数
constructor() {
// 初始化 API 实例
this.derivativesAPI = new DerivativesApi()
}
// 实例名成
name() {
return 'ExtractorSvc'
}
/**
* 【对外提供的 API】
* 将 SVF 文件全部下载到服务器,并返回所有文件的路径
* @param {AuthClient} oauth2Client 案例中定义的 getClient 方法生成的 token
* @param {AuthToken} credentials 案例中定义的 getInternalToken 方法生成的 token
* @param {string} urn 案例中 new ObjectsApi().getObjects API获取的 objectId
* @param {string} directory 存储资源的目标绝对路径
* @returns
*/
download(oauth2Client, credentials, urn, directory) {
return new Promise(async (resolve, reject) => {
// mkdirp:mkdir 的 promise 分装
// 创建目标目录,确保目录确实存在
await mkdirp(directory)
// 根据 URL 获取顶层的 manifest
const manifest = await this.derivativesAPI.getManifest(urn, {
}, oauth2Client, credentials)
// 整合要获取的全部资源
const derivatives = await this.getDerivatives(oauth2Client, credentials, manifest.body)
// 格式化资源信息,提取必要字段
const nestedDerivatives = derivatives.map(item => {
return item.files.map(file => {
const localPath = formatSep(path.resolve(directory, item.localPath))
return {
basePath: item.basePath,
guid: item.guid,
mime: item
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删