HTML5 WebGL 在三维中的应用,已经发展的如火如荼,使其在三维组态(工业控制)方面也变得简单易行! 三维组态软件提升了工业控制的管理效率,让工业控制的资源管理、风险管控获得很大的改善。前端
传统的三维组态通常都是本地应用, 该案例使用的是基于浏览器B/S架构下的三维组态的应用。node
该案例模拟的是一个油田简单的工业控制场景, 模型大体包括
油井、分离器、 加热炉、自然气、外输泵。
还包括管路流动、流动方向。 描述了采油、加工、 输出的全过程。程序员
第一步要作的就是建模,设计组使用3D建模工具 3d max或者c4d 进行油田设备模型的建模。建模后导出后缀为obj或者gltf格式文件,这两种格式是咱们三维渲染引擎支持最好的文件格式。后端
建模后的全部模型文件,最终会放到后端的模型库,模型库的管理目录,以下图所示:
浏览器
须要制做的模型包括油井、分离器、加热炉、自然气、外输泵,以下图所示,架构
加载模型可以使用引擎模型的加载函数,进行模型加载,如obj模型加载,以下代码所示:app
new mono.OBJMTLLoader().load( 'youjing.obj', 'youjing.mtl', '', (node)=> { node.type = 'obj'; box.addByDescendant(node); }, );
如加载一个油井模型,由于加载模型是一个异步的过程,因此会有一个回调函数,加载完成以后,在回调函数中,把模型文件生成的三维对象,加入到场景容器box之中,加入以后场景中就会显示咱们的三维对象,以下图所示:异步
建立Network3D对象,便可以建立三维场景对象,以下代码所示:ide
const box = new mono.DataBox(); const network = new TopoNetwork(box, null, 'monoCanvas'); network.mode = 'editor'; window.network = network; // todo this.network = network; network.bindApp(this); network.setRenderSelectFunction(() => false); make.Default.path = './static/myModellib/'; network.setClearColor(0, 0, 0); network.setClearAlpha(0); const directionalLight = new mono.DirectionalLight(0x333333, 0.3); directionalLight.setDirection(new mono.Vec3(0, 1, 1)); box.add(directionalLight); let pointLight = new mono.PointLight(0xeae5e1, 0.3); pointLight.setPosition(2000, 2000, 2000); box.add(pointLight); pointLight = new mono.PointLight(0xeae5e1, 0.4); pointLight.setPosition(-2000, 2000, 2000); box.add(pointLight); pointLight = new mono.PointLight(0xeae5e1, 0.3); pointLight.setPosition(2000, 2000, -2000); box.add(pointLight); pointLight = new mono.PointLight(0xeae5e1, 0.4); pointLight.setPosition(-2000, 2000, -2000); box.add(pointLight); box.add(new mono.AmbientLight(0x888888)); mono.Utils.autoAdjustNetworkBounds( network, document.querySelector('.app'), 'clientWidth', 'clientHeight', );
从模型列表,把模型拖拽到三维场景对象上,便可以建立模型对象,以下图所示:
函数
在模型按钮上,须要监听drag 或者dragstart事件,这个被封装到一个独立的类Dragger.js里面,在该类中专门处理了dragstart事件:
addDragger(parent, subClass, option) { parent.addEventListener('dragstart', (e) => { let target = null; // 拿到冒泡的全部元素 const path = eventPath(e); for (let i = 0; i < path.length; i += 1) { if (path[i].classList && path[i].classList.contains(subClass)) { target = path[i]; break; } } ... }
在三维场景中,能够直接经过打点的方式建立三维管道,以下代码所示:
let path = new mono.Path(pipePoints); path = mono.PathNode.prototype.adjustPath(path, 2, 2); const node = new mono.PathNode(path, 10, 3, 20); node.s({ 'm.type': 'phong', 'm.side': 'both', 'm.normalType': mono.NormalTypeSmooth, 'm.color': '#E35944', 'm.ambient': '#E35944', }); this.network.getDataBox().addByDescendant(node);
其中pipePoints是打点记录下的三维顶点。
管路动画是经过管路贴图的offset属性,不断变化造成的动态流动效果,以下代码所示:
node.animate = new mono.Animate({ from: pipeDirection === 'forward' ? 0 : 1, to: pipeDirection === 'forward' ? 1 : 0, dur: 1000, reverse: false, repeat: Number.POSITIVE_INFINITY, onUpdate(value) { node.setStyle('m.texture.offset', new mono.Vec2(value, 0)); }, });
最终效果以下图:
经过研发编辑,最终的显示效果大体以下:
还有更多效果本文并无凸显出来, 有兴趣获取demo的,请发邮件到:
terry.tan@servasoft.com
欢迎关注公众号“ITman彪叔”。彪叔,拥有10多年开发经验,现任公司系统架构师、技术总监、技术培训师、职业规划师。在计算机图形学、WebGL、前端可视化方面有深刻研究。对程序员思惟能力训练和培训、程序员职业规划有浓厚兴趣。