用 HTML5 与 WebGL 打造一个海上平台

前言

随着陆地油气资源逐渐减少,许多国家很早就将目光投向了海洋。无论是浅海石油钻采或是深海,所有的活动必须要在海上钻井平台上进行,与陆地上的钻井平台不同,海上钻井平台空间大小有限,被称为“流动的海上国土”, 需要综合考虑作业人员生活空间、钻井及安全救生设备等。事实上,海上平台还有几种不同的类型,而固定式生产平台形成了现代海上油田的基本特征。为了更加直观展示这种海上平台的风貌,下面就使用 HightopoHT for Web 产品(以下简称 HT)来构造一个轻量化的三维可视化场景,在浏览器上就可以一览无余。

预览地址:https://www.hightopo.com/demo/ht-offshore-platform/

场景搭建

关于海上平台的模型通过 3d Max 建模,导出为 objmtl 文件,在 HT 中通过解析 objmtl 文件来生成 3D 场景中所需的复杂模型,当然如果是简单的模型可以直接使用 HT 来绘制,这样会比 obj 模型更轻量化,因为 HT 都是采用 HTML5/WebGL 建模的方案。那么如何在浏览器端加载出这些模型呢?在建模工作完成后,HT 会生成一个 json 文件,而我们只需要在代码中创建视图组件 ht.graph3d.Graph3dView,再将其加入到 body 节点下,最后通过反序列化加载 json 文件便可呈现 3D 内容,代码如下:

var g3d = new ht.graph3d.Graph3dView();
// 得到 3D 视图组件的数据模型
var dm3d = g3d.getDataModel();
// 将 3D 组件加入到 body 下
g3d.addToDOM();
// 反序列化 json 文件
g3d.deserialize('海上平台.json');

接下来需要设置一下天空球避免鼠标滚出,并初始化视角,代码如下:

// 得到标签名为 sky 的天空球节点
var sky = dm3d.getDataByTag('sky');
g3d.setSkyBox(sky);
// 设置初始视角
g3d.setEye(-2216, 95212, -16);
g3d.setCenter(0, 0, 0);
// 设置近端与远端位置
g3d.setNear(10);
g3d.setFar(400000);

为了使场景更加逼真,我们可以选择开启阴影效果,需要注意的是要将不希望出现阴影的节点通过 node.s('shadow.cast', false) 关闭阴影效果。相关参数设置如下:

g3d.enableShadow({
    degreeX: 35,       // 投影 x 轴角度
    degreeZ: 10,      // 投影 z 轴角度
    quality: 4096,  // low / medium / high / ultra / 4096数值
    bias: -0.0009,     // 深度浮点偏差补足
    type: 'soft',     // none / hard / soft
    radius: 0.6,      // type 为 hard / soft 时,补充的边缘厚度,用来提供更柔和的边缘
    intensity: 0.5    // 阴影强度, 1 为黑色
});

开场镜头

我们希望在自由浏览 3D 场景之前有一个开场动画,这样仿佛有一种大场面既视感。最初的视角设定了一个俯视的视角,由俯视慢慢变为侧视,再通过一个全方位超大视角变换,最终靠近我们的主角——海上平台,为了让镜头更加平滑,这里使用 HT 中的管道动画 ,通过绘制一条 ht.Shape 类型的三维管道,配合 ht.Default.startAnim 动态获取管道路径上的关键点不断设置摄像机看向的位置即可,相关代码如下:

// 先获取绘制好的管道节点
var polyine = dm3d.getDataByTag('polyine');
// 开启动画
ht.Default.startAnim({
    duration: 10000,
    easing: function (t) {
        return t;
    },
    action: function (v, t) {
        // 获取管道信息
        var length = this.main.g3d.getLineLength(polyline),
            offset = this.main.g3d.getLineOffset(polyline, length * v),
            point = offset.point,
            px = point.x,
            py = point.y,
            pz = point.z;
        // 改变摄像机位置
        g3d.setEye(px, py, pz);
        g3d.setCenter(0, 0, 0);
    }
});

海水动画

如果海面风平浪静,那么一切将索然无味,所以当然要制造浪潮涌动的效果,这里通过控制一组轮播效果的海水节点的显示和隐藏来模拟真实海水的翻涌效果。具体代码如下:

// 通过 getChildren() 方法返回 ht.List 集合
var seawaterList = dm3d.getDataByTag('seawaterList').getChildren();
// 通过 size() 方法判断集合大小
var size = seawaterList.size();
var index = 0;
// 通过 callLater() 函数循环控制各节点的显隐
var cb = function () {
    seawaterList.get(index % size).s('3d.visible', false);
    seawaterList.get((index + 2) % size).s('3d.visible', true);
    index = (index + 1) % size;
    ht.Default.callLater(cb, this, null, 200);
};
ht.Default.callLater(cb);

有了海水翻滚,自然少不了海浪拍打,浪花动画通过随机改变多个浪花模型的不透明度以及位置实现:

// 设置不透明度
beachwave.setStyle("shape3d.opacity", random);
// 设置位置
beachwave.setPosition3d(x * random, y, z);

另外可以参考这种方式控制平台周围圆圈的旋转展示风向、风力、安全作业事件、钻井启用等信息,通过调用 node.setRotation() 即可。

吊机动画

海上作业少不了平台上吊机一系列运动动作,我们可以使用 ht.Default.startAnim 来模拟吊机具体的作业情况,在一段动画代码执行完成后可以在 finishFunc 中继续执行后续相关操作。

总结

以上就是一些关于海上钻井平台的展示情况。事实上,海上平台可以分为好几个不同的种类,每种类型的平台的结构以及技术复杂程度都是不一样的,特别是深海作业对这种平台的技术要求就更高。从全球范围来看,各大石油公司对于浅海油气资源的勘探与开采早已开始,而深水甚至超深水的石油钻探项目变得更加普遍和必要,随之而来的便是海上作业平台的安全性问题。

海上钻井平台除了空间小,还需要在复杂的海况情况下维持稳定性,毕竟它要面对诸多不确定的自然因素,如风力、波浪力、冰力、流力、地震力等,所以一旦在某一方面有偏差,将会酿成难以估量的灾难性后果。实际上结合 HT ,可以根据后台实时数据,对海上平台的设备运行情况,人员信息,海上作业环境等指标进行实时监控,进一步确保海上平台作业的安全性。要知道什么为之灾难性后果,千言万语,不如一图:

猜你喜欢

转载自www.cnblogs.com/htdaydayup/p/12483898.html