精华内容
下载资源
问答
  • 作者:Gvonte,关键技术点:效果合成器EffectComposer实现部分辉光效果,加入抗锯齿,高级效果组合器 MaskPass。
  • 3D可视化机房运营全景管控平台建设方案 数据中心3D可视化项目建设方案
  • 3D可视化机房运营全景管控平台
  • 3D可视化机房运营全景管控平台建设方案 数据中心3D可视化项目建设方案
  • 3D可视化机房运营全景管控平台建设综合解决方案 数据中心3D可视化项目建设方案
  • 玩玩3D可视化,要做一个3D可视化机房。 参考文档 疑难问题 渲染围墙时图片糊了 黄色区域就是糊的,绿色区域就是好的 这是围墙 奇怪的是,只有前后方向的贴图糊了,其它没事 先查看渲染围墙这部分的代码 再看看加载...
  • 3D可视化机房运营全景管控平台建设综合解决方案 数据中心3D可视化项目建设方案
  • 前言用 WebGL 渲染的 3D 机房现在也不是什么新鲜事儿了,这篇文章的主要目的是说明一下,3D 机房中的 eye 和 center 的问题,刚好在项目中用上了,好生思考了一番,最终觉得这个例子最符合我的要求,就拿来作为记录...

    前言

    用 WebGL 渲染的 3D 机房现在也不是什么新鲜事儿了,这篇文章的主要目的是说明一下,3D 机房中的 eye 和 center 的问题,刚好在项目中用上了,好生思考了一番,最终觉得这个例子最符合我的要求,就拿来作为记录。

    demo演示地址:http://hightopo.com/demo/3DRoom/index.html

    效果图:
    图片描述
    这个 3D 机房的 Demo 做的还不错,比较美观,基础的交互也都满足,接下来看看怎么实现。

    代码生成

    定义类

    首先从 index.html 中调用的 js 路径顺序一个一个打开对应的 js,server.js 中自定义了一个 Editor.Server 类由 HT 封装的 ht.Default.def 函数创建的(注意,创建的类名 Editor.Server 前面的 Editor 不能用 E 来替代):

    ht.Default.def('Editor.Server', Object, { // 第一个参数为类名,如果为字符串,自动注册到 HT 的 classMap 中;第二个参数为此类要继承的父类;第三个参数为方法和变量的声明
        addToDataModel: function(dm) { // 将节点添加进数据容器
            dm.add(this._node); // ht 中的预定义函数,将节点通过 add 方法添加进数据容器中
        },
        setHost: function() { // 设置吸附
            this._node.setHost.apply(this._node, arguments); 
        },
        s3: function() { // 设置节点的大小
            this._node.s3.apply(this._node, arguments);
        },
        setElevation: function() { // 控制Node图元中心位置所在3D坐标系的y轴位置
            this._node.setElevation.apply(this._node, arguments);
        }
    });
    

    创建 Editor.Server 类

    图片描述
    这个类可以创建一个 ht.Node 节点,并设置节点的颜色和前面贴图:

    var S = E.Server = function(obj) { // 服务器组件
        var color = obj.color, 
            frontImg = obj.frontImg;
    
        var node = this._node = new ht.Node(); // 创建节点
        node.s({ // 设置节点的样式 s 为 setStyle 的缩写
            'all.color': color, // 设置节点六面的颜色
            'front.image': frontImg // 设置节点正面的图片
        });
    };
    

    这样我在需要创建服务器组件的位置直接 new 一个新的服务器组件对象即可,并且能够直接调用我们上面声明的 setHost 等函数,很快我们就会用上。

    接下来创建 Editor.Cabinet 机柜类 ,方法跟上面 Editor.Server 类的定义方法差不多:

    ht.Default.def('Editor.Cabinet', Object, {
        addToDataModel: function(dm) {
            dm.add(this._door);
            dm.add(this._node);
            this._serverList.forEach(function(s) { 
                s.addToDataModel(dm); 
            });
        },
        p3: function() { 
            this._node.p3.apply(this._node, arguments); // 设置节点的 3d 坐标
        }
    });
    

    创建 Editor.Cabinet 类

    图片描述
    这个类相对于前面的 Editor.Server 服务器组件类要相对复杂一点,这个类中创建了一个柜身、柜门以及机柜内部的服务器组件:

    var C = E.Cabinet = function(obj) {
        var color = obj.color,
            doorFrontImg = obj.doorFrontImg,
            doorBackImg = obj.doorBackImg,
            s3 = obj.s3;
    
        var node = this._node = new ht.Node(); // 柜身
        node.s3(s3); // 设置节点的大小为 setSize3d
        node.a('cabinet', this); // 自定义 cabinet 属性
        node.s({ // 设置节点的样式为 setStyle
            'all.color': color, // 设置节点六面的颜色
            'front.visible': false // 设置节点前面是否可见
        });
    
        if (Math.random() > 0.5) {
            node.addStyleIcon('alarm', { // 向节点上添加 icon 图标
                names: ['icon 温度计'], // 包含多个字符串的数组,每个字符串对应一张图片或矢量(通过 ht.Default.setImage 注册)
                face: 'top', // 默认值为 front,图标在 3D 下的朝向,可取值 left|right|top|bottom|front|back|center
                position: 17, // 指定 icons 的位置
                autorotate: 'y', // 默认值为 false,图标在 3D 下是否自动朝向眼睛的方向
                t3: [0, 16, 0], // 默认值为 undefined,图标在 3D 下的偏移,格式为[x,y,z]
                width: 37, // 指定每个 icon 的宽度,默认根据注册图片时的宽度
                height: 32, // 指定每个 icon 的高度,默认根据注册图片时的高度
                textureScale: 4, // 默认值为 2,该值代表内存实际生成贴图的倍数,不宜设置过大否则影响性能
                visible: { func: function() { return !!E.alarmVisible; }} // 表示该组图片是否显示
            });
        }
    
        var door = this._door = new ht.DoorWindow(); // 柜门
        door.setWidth(s3[0]); // 置图元在 3D 拓扑中的 x 轴方向的长度
        door.setHeight(1); // 设置图元在 3D 拓扑中的 z 轴长度
        door.setTall(s3[1]); // 控制 Node 图元在 y 轴的长度
        door.setElevation(0); // 设置图元中心在 3D 坐标系中的y坐标
        door.setY(s3[2] * 0.5); // 设置节点在 y 轴的位置
        door.setHost(node); // 设置吸附
        door.s({ // 设置节点样式 setStyle
            'all.color': color, // 设置节点六面颜色
            'front.image': doorFrontImg, // 设置节点正面图片
            'front.transparent': true, // 设置节点正面是否透明
            'back.image': doorBackImg, // 设置节点背面的图片
            'back.uv': [1,0, 1,1, 0,1, 0,0], // 自定义节点后面 uv 贴图,为空采用默认值 [0,0, 0,1, 1,1, 1,0]
            'dw.axis': 'right' // 设置 DoorWindow 图元展开和关闭操作的旋转轴,可取值 left|right|top|bottom|v|h
        });
    
        var serverList = this._serverList = []; 
        var max = 6,
            list = E.randomList(max, Math.floor(Math.random() * (max - 2)) + 2); // global.js 中声明的获取随机数的函数 
        var server, h = s3[0] / 4;
        list.forEach(function(r) {
            var server = new E.Server({ // 服务器组件
                color: 'rgb(51,49,49)',
                frontImg: '服务器 组件精细'
            });
            server.s3(s3[0] - 2, h, s3[2] - 4); // 设置节点大小
            server.setElevation((r - max * 0.5) * (h + 2)); // 设置节点中心点在 y 轴的坐标
            server.setHost(node); // 设置节点的吸附
    
            serverList.push(server); // 向 serverList 中添加 server 节点
        });
    };
    

    上面代码中唯一没提到的是 Editor.randomList 函数,这个函数是在 global.js 文件中声明的,声明如下:

    var E = window.Editor = {
        leftWidth: 0,
        topHeight: 40,
        randomList: function(max, size) {
            var list = [], ran;
            while (list.length < size) {
                ran = Math.floor(Math.random() * max);
                if (list.indexOf(ran) >= 0) 
                    continue;
                list.push(ran);
            }
            return list;
        }
    };
    

    好了,场景中的各个部分的类都创建完成,那我们就该将场景创建起来,然后将这些图元都堆进去!

    界面设计

    场景创建

    如果熟悉的同学应该知道,用 HT 创建一个 3D 场景只需要 new 一个 3D 组件,再将通过 addToDOM 函数将这个场景添加进 body 中即可:

    var g3d = E.main = new ht.graph3d.Graph3dView(); // 3d 场景
    

    main.js 文件中主要做的是在 3D 场景中一些必要的元素,比如墙面,地板,门,空调以及所有的机柜的生成和排放位置,还有非常重要的交互部分。

    墙体,地板,门,空调和机柜的创建我就不贴代码出来了,有兴趣的请自行查看代码,这里主要说一下双击机柜以及与机柜有关的任何物体(柜门,服务器设备)则 3D 中 camera 的视线就会移动到双击的机柜的前方某个位置,而且这个移动是非常顺滑的,之前技艺不精,导致这个部分想了很久,最后参考了这个 Demo 的实现方法。

    为了能够重复地设置 eye 和 center,将设置这两个参数对应的内容封装为 setEye 和 setCenter 方法,setCenter 方法与 setEye 方法类似,这里不重复赘述:

    // 设置眼睛位置
    var setEye = function(eye, finish) {
        if (!eye) return;
        var e = g3d.getEye().slice(0), // 获取当前 eye 的值
            dx = eye[0] - e[0],
            dy = eye[1] - e[1],
            dz = eye[2] - e[2];
        // 启动 500 毫秒的动画过度
        ht.Default.startAnim({
            duration: 500,
            easing: easing, // 动画缓动函数
            finishFunc: finish || function() {}, // 动画结束后调用的函数
            action: function(v, t) { // 设置动画 v 代表通过 easing(t) 函数运算后的值,t 代表当前动画进行的进度[0~1],一般属性变化根据 v 参数进行
                g3d.setEye([ //设置 3D 场景中的 eye 眼睛的值,为一个数组,分别对应 x,y,z 轴的值 
                    e[0] + dx * v,
                    e[1] + dy * v,
                    e[2] + dz * v
                ]);
            }
        });
    };
    

    我没有重复声明 setCenter 函数不代表这个函数不重要,恰恰相反,这个函数在“视线”移动的过程中起到了决定性的作用,上面的 setEye 函数相当于我想走到我的目标位置的前面(至少我定义的时候是这种用途),而 setCenter 的定义则是将我的视线移到了目标的位置(比如我可以站在我现在的位置看我右后方的物体,也可以走到我右后方去,站在那个物体前面看它),这点非常重要,请大家好好品味一下。

    双击事件倒是简单,只要监听 HT 封装好的事件,判断事件类型,并作出相应的动作即可:

    g3d.mi(function(e) { // addInteractorListener 事件监听函数
        if (e.kind !== 'doubleClickData') // 判断事件类型为双击节点
            return;
        var data = e.data, p3;
    
        if (data.a('cabinet')) // 机身
            p3 = data.p3();
        else {
            host = data.getHost(); // 获取点击节点的吸附对象
            if (host && host.a('cabinet')) { // 如果吸附对象为 cabinet
                p3 = host.p3();
            }
        }
    
        if (!p3) return;
    
        setCenter(p3); // 设置 center 目标的要移向位置为 cabinet 的位置
        setEye([p3[0], 211, p3[2] + 247]); // 设置 eye 眼睛要移向的位置
    });
    

    顶部导航栏

    图片描述
    一开始看到这个例子的时候我在想,这人好厉害,我用 HT 这么久,用 HT 的 ht.widget.Toolbar 还没能做出这么漂亮的效果,看着看着发现这原来是用 form 表单做的,厉害厉害,我真是太愚钝了。

    var form = E.top = new ht.widget.FormPane(); // 顶部 表单组件
    form.setRowHeight(E.topHeight); // 设置行高
    form.setVGap(-E.topHeight); // 设置表单组件水平间距 设置为行高的负值则可以使多行处于同一行
    form.setVPadding(0); // 设置表单顶部和顶部与组件内容的间距
    form.addRow([null, { // 向表单中添加一行组件,第一个参数为元素数组,元素可为字符串、json 格式描述的组件参数信息、html 元素或者为 null
        image: {
            icon: './symbols/inputBG.json',
            stretch: 'centerUniform'
        }
    }], [40, 260]); // 第二个参数为每个元素宽度信息数组,宽度值大于1代表固定绝对值,小于等于1代表相对值,也可为80+0.3的组合
    form.addRow([null, null, {
        id: 'searchInput',
        textField: {}
    }, {
        element: '机房可视化管理系统',
        color: 'white',
        font: '18px arial, sans-serif'
    }, null, {
        button: {
            // label: '视图切换',
            icon: './symbols/viewChange.json',
            background: null,
            selectBackground: 'rgb(128,128,128)',
            borderColor: 'rgba(0, 0, 0, 0)',
            onClicked: function() {
                E.focusTo();
            }
        }
    }, null, {
        button: {
            // label: '告警',
            icon: './symbols/alarm.json',
            togglable: true,
            selected: false,
            background: null,
            selectBackground: 'rgb(128,128,128)',
            borderColor: 'rgba(0, 0, 0, 0)',
            onClicked: function(e) {
                E.setAlarmVisible(this.isSelected());
            }
        }
    }, null], [40, 42, 218, 300, 0.1, 50, 10, 50, 10]);
    

    以上都只是能实现,但是并没有真正地添加进 html 标签中,也就意味着,现在界面上什么都没有!别忘了在页面加载的时候将 3D 场景添加进 body 中,同时也别忘了将 form 表单添加进 body 中,并且设置窗口大小变化事件时,form 表单也需要实时更新:

    window.addEventListener('load', function() {
        g3d.addToDOM(); // 将 3D 场景添加进 body 中
    
        document.body.appendChild(E.top.getView()); //将 form 表单组件底层 div 添加进 body 中
    
        window.addEventListener('resize', function() { // 窗口大小变化事件监听
            E.top.iv(); // 更新 form 表单的底层 div 
        });
    });
    

    这里说明一下 addToDOM 函数,对于了解 HT 的机制非常重要。HT 的组件一般都会嵌入 BorderPane、SplitView 和 TabView 等容器中使用,而最外层的 HT 组件则需要用户手工将 getView() 返回的底层 div 元素添加到页面的 DOM 元素中,这里需要注意的是,当父容器大小变化时,如果父容器是 BorderPane 和 SplitView 等这些 HT 预定义的容器组件,则 HT 的容器会自动递归调用孩子组件invalidate 函数通知更新。但如果父容器是原生的 html 元素, 则 HT 组件无法获知需要更新,因此最外层的 HT 组件一般需要监听 window 的窗口大小变化事件,调用最外层组件 invalidate 函数进行更新。

    为了最外层组件加载填充满窗口的方便性,HT 的所有组件都有 addToDOM 函数,其实现逻辑如下,其中 iv 是 invalidate 的简写:

    addToDOM = function(){   
        var self = this,
            view = self.getView(),   
            style = view.style;
        document.body.appendChild(view); // 将场景的底层 div 添加进 body 中           
        style.left = '0'; // HT 默认将所有的组件底层 div 的 position 设置为 absolute
        style.right = '0';
        style.top = '0';
        style.bottom = '0';      
        window.addEventListener('resize', function () { self.iv(); }, false); // 窗口大小变化监听事件,通知组件变化更新          
    }
    

    这样,所有的代码就结束了,可以自己右键“检查”,network 中可以获取相对应的 json 文件。

    展开全文
  • 数据中心3D可视化项目建设方案 3D可视化机房运营全景管控平台建设方案
  • 3D可视化机房运营全景管控平台建设方案 数据中心3D可视化项目建设方案
  • 3D可视化机房运营全景管控平台建设综合解决方案 数据中心3D可视化项目建设方案
  • 智慧方案
  • 3D可视化,就是把复杂抽象的数据...3D可视化机房管理系统的出现,大幅度提高了机房可视化、数字化水平,其集中管控的特性更高效地增强了机房管理与维护的能力。  数据中心3D可视化管理  数据中心3D可视化管理基...

    3D可视化,就是把复杂抽象的数据信息,以合适的视觉元素及视角去呈现,方便大家理解、记忆、传递!因此,我们需要将影响应用系统稳定运行的几个要素数据可视化。
      互联网时代,用户业务规模急速扩增,导致传统机房的管理难度愈加困难。3D可视化机房管理系统的出现,大幅度提高了机房可视化、数字化水平,其集中管控的特性更高效地增强了机房管理与维护的能力。
      数据中心3D可视化管理
      数据中心3D可视化管理基于3D互动场景浏览技术,直观展现设备与环境场景,依托于对可视化与数据中心管理结合方面的设计思路和长期思考,针对性地设计了一套先进自主的技术架构:数据中心可视化系统采用B/S架构,可基于IE访问,易于使用。
      权限管理,系统提供基于账号、角色、设备组的综合权限管理能力。通过角色控制用户访问系统功能模块的权限。当用户可以访问某个功能模块时,可通过设备组控制用户访问数据的权限。
      多数据中心管理,系统中可以管理多个数据中心的3D场景,清晰展示各数据中心在地图上的位置。点击某个数据中心,可进入其对应的3D园区中。
      便捷的3D操控,系统在3D可视化管理环境中采用逐级放大进入方式,实现园区(数据中心),楼层,机房,机柜组和机柜,设备,端口,线缆七级全三维浏览和全鼠标操作。可通过鼠标对3D场景实现放大/缩小、上下左右的平移和任意角度旋转、查看整体环境等操作。
      数据中心3D可视化管理,使得机房运维更高效,企业运营更增值。

    展开全文
  • 浅谈:3D可视化机房管理系统!

    千次阅读 2019-03-18 14:28:13
    3D可视化,就是把复杂抽象的数据...3D可视化机房管理系统的出现,大幅度提高了机房可视化、数字化水平,其集中管控的特性更高效地增强了机房管理与维护的能力。下面简单说说。  一、传统机房管理系统存在的问题  1...

    3D可视化,就是把复杂抽象的数据信息,以合适的视觉元素及视角去呈现,方便大家理解、记忆、传递!因此,我们需要将影响应用系统稳定运行的几个要素数据可视化。
      互联网时代,用户业务规模急速扩增,导致传统机房的管理难度愈加困难。3D可视化机房管理系统的出现,大幅度提高了机房可视化、数字化水平,其集中管控的特性更高效地增强了机房管理与维护的能力。下面简单说说。
      一、传统机房管理系统存在的问题
      1.机房现场管理与设备信息管理系统之间缺乏联系,信息集中及协同程度低;设备数量众多,维护人员分区域巡检或维护设备耗时耗力;
      2.分布范围广,机房内设备复杂多样,包括交换、数据、动力、传输等不同专业的各类设备,传统模式下各设备归属对口专业人员,机房管理员面对多专业交叉的现场管理难度大。
      正是因为传统机房管理存在种种难题,所以才驱使了可视化机房的诞生,那么它有什么功能呢?
      二、3D可视化机房管理系统的功能
      1.共有3D机房编辑、3D展示、数据库三个子系统,主要可实现机房平面可视化、设备资产可视化、动力环境监控可视化、配线可视化、统计与查询五大功能。
      2.机房管理系统利用3D机房编辑器快速生成机房三维模型,以3D可视化方式高精度呈现机房内环境场景,并以开放的数据接口与现有各类设备信息管理系统进行数据对接,将形象化的虚拟场景和真实数据相结合,可快速、灵活地实现动环监测、资产管理、记录查询、统计分析、故障告警等功能的直观展示。
      3.还可实现机房巡视检修记录电子化管理,实时监控动环设备的报警信息,快速定位报警设备,缩短设备检修时间;利用现有实时数据结合应急预案,还可进行事故应急处理及预案推演。
      4.系统投入使用后,每日机房巡检、登记可由此前1小时缩短为0.2小时,资产信息现场核查缩短4小时,设备查找与故障定位效率提升67%,系统应用范围广,具有较高的易复制性。

    展开全文
  • 可视化机房设备编辑软件, 而通过VisualNet平台实现的各种资源管理系统,由于要求的员工技术门槛低,只需把图纸画好、把数据录入进去,就能快速搭建起一套专业化的管理系统来。省去了程序开发、代码编写的过程 ,对...
  • 基于 HTML5 的 3D 机房可视化实景监控

    千次阅读 2019-04-02 08:30:07
    围绕如何提高、管理和有效利用前端设备采集的海量信息为公共安全服务,特别是在技术融合大趋势下,如何结合当前先进的视频融合,虚实融合、三维动态等技术,实现三维场景实时动态可视化监控,更有效的识别、分析、...

    前言

    随着视频监控联网系统的不断普及和发展, 网络摄像机更多的应用于监控系统中,尤其是高清时代的来临,更加快了网络摄像机的发展和应用。

    在监控摄像机数量的不断庞大的同时,在监控系统中面临着严峻的现状问题:海量视频分散、孤立、视角不完整、位置不明确等问题,始终围绕着使用者。因此,如何更直观、更明确的管理摄像机和掌控视频动态,已成为提升视频应用价值的重要话题。所以当前项目正是从解决此现状问题的角度,应运而生。围绕如何提高、管理和有效利用前端设备采集的海量信息为公共安全服务,特别是在技术融合大趋势下,如何结合当前先进的视频融合,虚实融合、三维动态等技术,实现三维场景实时动态可视化监控,更有效的识别、分析、挖掘海量数据的有效信息服务公共应用,已成为视频监控平台可视化发展的趋势和方向。目前,在监控行业中,海康、大华等做监控行业领导者可基于这样的方式规划公共场所园区等的摄像头规划安放布局,可以通过海康、大华等摄像头品牌的摄像头参数,调整系统中摄像头模型的可视范围,监控方向等,更方便的让人们直观的了解摄像头的监控区域,监控角度等。

    以下是项目地址:基于 HTML5 的 WebGL 自定义 3D 摄像头监控模型

    效果预览

    整体场景-摄像头效果图

    整体场景

    局部场景-摄像头效果图

    局部场景

    代码生成

    摄像头模型及场景

    项目中使用的摄像头模型是通过 3dMax 建模生成的,该建模工具可以导出 obj 与 mtl 文件,在 HT 中可以通过解析 obj 与 mtl 文件来生成 3d 场景中的摄像头模型。

    项目中场景通过 HT 的 3d 编辑器进行搭建,场景中的模型有些是通过 HT 建模,有些通过 3dMax 建模,之后导入 HT 中,场景中的地面白色的灯光,是通过 HT 的 3d 编辑器进行地面贴图呈现出来的效果。

    锥体建模

    3D 模型是由最基础的三角形面拼接合成,例如 1 个矩形可以由 2 个三角形构成,1 个立方体由 6 个面即 12 个三角形构成, 以此类推更复杂的模型可以由许多的小三角形组合合成。因此 3D 模型定义即为对构造模型的所有三角形的描述, 而每个三角形由三个顶点 vertex 构成, 每个顶点 vertex 由 x, y, z 三维空间坐标决定,HT 采用右手螺旋定则来确定三个顶点构造三角形面的正面。

    HT 中通过 ht.Default.setShape3dModel(name, model) 函数,可注册自定义 3D 模型,摄像头前方生成的锥体便是通过该方法生成。可以将该锥体看成由 5 个顶点,6 个三角形组成,具体图如下:

    锥体

    ht.Default.setShape3dModel(name, model)

    • name 为模型名称,如果名称与预定义的一样,则会替换预定义的模型
    • model 为 JSON 类型对象,其中 vs 表示顶点坐标数组,is 表示索引数组,uv 表示贴图坐标数组,如果想要单独定义某个面,可以通过***bottom_vs,bottom_is,bottom_uv,top_vs,top_is, top_uv*** 等来定义,之后便可以通过 ***shape3d.top.*, shape3d.bottom.* *** 等单独控制某个面

    以下是我定义模型的代码:

    // camera 是当前的摄像头图元
    // fovy 为摄像头的张角的一半的 tan 值
    var setRangeModel = function(camera, fovy) {
    	var fovyVal = 0.5 * fovy;
        var pointArr = [0, 0, 0, 
        				-fovyVal, fovyVal, 0.5, 
                        fovyVal, fovyVal, 0.5, 
                        fovyVal, -fovyVal, 0.5, 
                        -fovyVal, -fovyVal, 0.5];
        ht.Default.setShape3dModel(camera.getTag(), [{
            vs: pointArr,
            is: [2, 1, 0, 
                 4, 1, 0, 
                 4, 3, 0, 
                 3, 2, 0],
            from_vs: pointArr.slice(3, 15),
            from_is: [3, 1, 0, 
                      3, 2, 1],
            from_uv: [0, 0, 
                      1, 0, 
                      1, 1, 
                      0, 1]
        }]);
    }
    

    我将当前摄像头的 tag 标签值作为模型的名称,tag 标签在 HT 中用于唯一标识一个图元,用户可以自定义 tag 的值。通过 pointArr 记录当前五面体的五个顶点坐标信息,代码中通过 from_vs, from_is, from_uv 单独构建五面体底面,底面用于显示当前摄像头呈现的图像。

    代码中设置了锥体 style 对象的 wf.geometry 属性,通过该属性可以为锥体添加模型的线框,增强模型的立体效果,并且通过 wf.color,wf.width 等参数调节线框的颜色,粗细等。

    相关模型 style 属性的设置代码如下:

    rangeNode.s({
            'shape3d': cameraName, // 摄像头模型名称
            'shape3d.color': 'rgba(52, 148, 252, 0.3)', // 锥体模型颜色
            'shape3d.reverse.flip': true, // 锥体模型的反面是否显示正面的内容
            'shape3d.light': false, // 锥体模型是否受光线影响
            'shape3d.transparent': true, // 锥体模型是否透明
            '3d.movable': false, // 锥体模型是否可移动
            'wf.geometry': true // 是否显示锥体模型线框
    });
    

    摄像头图像生成原理

    透视投影

    透视投影是为了获得接近真实三维物体的视觉效果而在二维的纸或者画布平面上绘图或者渲染的一种方法,它也称为透视图。 透视使得远的对象变小,近的对象变大,平行线会出现先交等更更接近人眼观察的视觉效果。

    透视投影

    如上图所示,透视投影最终显示到屏幕上的内容只有截头锥体( View Frustum )部分的内容, 因此 Graph3dView 提供了 eye, center, up, far,near,fovy 和 aspect 参数来控制截头锥体的具体范围。具体的透视投影可以参考 HT for Web3D 手册。

    根据上图的描述,在本项目中可以在摄像头初始化之后,缓存当前 3d 场景 eyes 眼睛的位置,以及 center 中心的位置,之后将 3d 场景 eyes 眼睛和 center 中心设置成摄像头中心点的位置,然后在这个时刻获取当前 3d 场景的截图,该截图即为当前摄像头的监控图像,之后再将 3d 场景的 center 与 eyes 设置成开始时缓存的 eyes 与 center 位置,通过该方法即可实现 3d 场景中任意位置的快照,从而实现摄像头监控图像实时生成。

    相关伪代码如下:

    	function getFrontImg(camera, rangeNode) {
    		var oldEye = g3d.getEye();
    		var oldCenter = g3d.getCenter();
    		var oldFovy = g3d.getFovy();
    		g3d.setEye(摄像头位置);
    		g3d.setCenter(摄像头朝向);
    		g3d.setFovy(摄像头张角);
    		g3d.setAspect(摄像头宽高比);
    		g3d.validateImp();
    		g3d.toDataURL();
    		g3d.setEye(oldEye);;
    		g3d.setCenter(oldCenter);
    		g3d.setFovy(oldFovy);
    		g3d.setAspect(undefined);
    		g3d.validateImp();
    	}
    

    经过测试之后,通过该方法进行图像的获取会导致页面有所卡顿,因为是获取当前 3d 场景的整体截图,由于当前3d场景是比较大的,所以 toDataURL 获取图像信息是非常慢的,因此我采取了离屏的方式来获取图像,具体方式如下:

    1. 创建一个新的 3d 场景,将当前场景的宽度与高度都设置为 200px 的大小,并且当前 3d 场景的内容与主屏的场景是一样的,HT中通过 new ht.graph3d.Graph3dView(dataModel) 来新建场景,其中的 dataModel 为当前场景的所有图元,所以主屏与离屏的 3d 场景都共用同一个 dataModel,保证了场景的一致。
    2. 将新创建的场景位置设置成屏幕看不到的地方,并且添加进 dom 中。
    3. 将之前对主屏获取图像的操作变成对离屏获取图像的操作,此时离屏图像的大小相对之前主屏获取图像的大小小很多,并且离屏获取不需要保存原来的眼睛 eyes 的位置以及 center 中心的位置,因为我们没有改变主屏的 eyes 与 center 的位置, 所以也减少的切换带来的开销,大大提高了摄像头获取图像的速度。

    以下是该方法实现的代码:

    function getFrontImg(camera, rangeNode) {
    		// 截取当前图像时将该摄像头所属的五面体隐藏
    		rangeNode.s('shape3d.from.visible', false); 
    		rangeNode.s('shape3d.visible', false);
            rangeNode.s('wf.geometry', false);
    		var cameraP3 = camera.p3();
    		var cameraR3 = camera.r3();
    		var cameraS3 = camera.s3();
    		var updateScreen = function() {
            	 demoUtil.Canvas2dRender(camera, outScreenG3d.getCanvas());
                 rangeNode.s({
                 'shape3d.from.image': camera.a('canvas')
                 });
                 rangeNode.s('shape3d.from.visible', true);
                 rangeNode.s('shape3d.visible', true);
                 rangeNode.s('wf.geometry', true);
    		};
            
    		// 当前锥体起始位置
    		var realP3 = [cameraP3[0], cameraP3[1] + cameraS3[1] / 2, cameraP3[2] + cameraS3[2] / 2]; 
            // 将当前眼睛位置绕着摄像头起始位置旋转得到正确眼睛位置
    		var realEye = demoUtil.getCenter(cameraP3, realP3, cameraR3); 
    
    		outScreenG3d.setEye(realEye);
    		outScreenG3d.setCenter(demoUtil.getCenter(realEye, [realEye[0], realEye[1] ,realEye[2] + 5], cameraR3));
    		outScreenG3d.setFovy(camera.a('fovy'));
    		outScreenG3d.validate();
    		updateScreen();
    }
    

    上面代码中有一个 getCenter 方法是用于获取 3d 场景中点 A 绕着点 B 旋转 angle 角度之后得到的点 A 在 3d 场景中的位置,方法中采用了 HT 封装的 ht.Math 下面的方法,以下为代码:

     // pointA 为 pointB 围绕的旋转点
     // pointB 为需要旋转的点
     // r3 为旋转的角度数组 [xAngle, yAngle, zAngle] 为绕着 x, y, z 轴分别旋转的角度 
     var getCenter = function(pointA, pointB, r3) {
            var mtrx = new ht.Math.Matrix4();
            var euler = new ht.Math.Euler();
            var v1 = new ht.Math.Vector3();
            var v2 = new ht.Math.Vector3();
    
            mtrx.makeRotationFromEuler(euler.set(r3[0], r3[1], r3[2]));
    
            v1.fromArray(pointB).sub(v2.fromArray(pointA));
            v2.copy(v1).applyMatrix4(mtrx);
            v2.sub(v1);
    
            return [pointB[0] + v2.x, pointB[1] + v2.y, pointB[2] + v2.z];
      };
    

    这里应用到向量的部分知识,具体如下:

    O ⃗ A + O ⃗ B = O ⃗ C \vec OA + \vec OB = \vec OC O A+O B=O C

    向量

    方法分为以下几个步骤求解:

    1. var mtrx = new ht.Math.Matrix4() 创建一个转换矩阵,通过 mtrx.makeRotationFromEuler(euler.set(r3[0], r3[1], r3[2])) 获取绕着 r3[0],r3[1],r3[2] 即 x 轴,y 轴,z 轴旋转的旋转矩阵。
    2. 通过 new ht.Math.Vector3() 创建 v1,v2 两个向量。
    3. v1.fromArray(pointB) 为建立一个从原点到 pointB 的一个向量。
    4. v2.fromArray(pointA) 为建立一个从原点到 pointA 的一个向量。
    5. v1.fromArray(pointB).sub(v2.fromArray(pointA)) 即向量 OB - OA 此时得到的向量为 AB,此时 v1 变为向量 AB。
    6. v2.copy(v1) v2 向量拷贝 v1 向量,之后通过 v2.copy(v1).applyMatrix4(mtrx) 对 v2 向量应用旋转矩阵,变换之后即为 v1向量绕着 pointA 旋转之后的的向量 v2。
    7. 此时通过 v2.sub(v1) 就获取了起始点为 pointB,终点为 pointB 旋转之后点构成的向量,该向量此时即为 v2。
    8. 通过向量公式得到旋转之后的点为 [pointB[0] + v2.x, pointB[1] + v2.y, pointB[2] + v2.z]。

    项目中的 3D 场景例子其实是 Hightopo 最近贵州数博会,HT 上工业互联网展台的 VR 示例,大众对 VR/AR 的期待很高,但路还是得一步步走,即使融资了 23 亿美金的 Magic Leap 的第一款产品也只能是 Full of Shit,这话题以后再展开,这里就上段当时现场的视频照片:

    现场

    2d 图像贴到 3d 模型

    通过上一步的介绍我们可以获取当前摄像机位置的截屏图像,那么如何将当前图像贴到前面所构建的五面体底部呢?前面通过 from_vs, from_is 来构建底部的长方形,所以在 HT 中可以通过将五面体的 style 中 shape3d.from.image 属性设置成当前图像,其中 from_uv 数组用来定义贴图的位置,具体如下图:

    贴图

    以下为定义贴图位置 from_uv 的代码:

    from_uv: [
        0, 0,
        1, 0,
        1, 1,
        0, 1
    ]
    

    from_uv 就是定义贴图的位置数组,根据上图的解释,可以将 2d 图像贴到 3d 模型的 from 面。

    控制面板

    HT 中通过 new ht.widget.Panel() 来生成如下图的面板:

    控制面板

    面板中每个摄像头都有一个模块来呈现当前监控图像,其实这个地方也是一个 canvas,该 canvas 与场景中锥体前面的监控图像是同一个 canvas,每一个摄像头都有一个自己的 canvas 用来保存当前摄像头的实时监控画面,这样就可以将该 canvas 贴到任何地方,将该 canvas 添加进面板的代码如下:

    formPane.addRow([{ 
    				element: camera.a('canvas')
                }], 240, 240);
    

    代码中将 canvas 节点存储在摄像头图元的 attr 属性下面,之后便可以通过 camera.a(‘canvas’) 来获取当前摄像头的画面。

    在面板中的每一个控制节点都是通过 formPane.addRow 来进行添加,具体可参考 HT for Web 的表单手册。之后通过 ht.widget.Panel 将表单面板 formPane 添加进 panel 面板中,具体可参考 HT for Web 的面板手册

    部分控制代码如下:

    formPane.addRow([
                      'rotateY',
                      {
                      	slider: {
                      		min: - Math.PI,
                            max: Math.PI,
                            value: r3[1],
                            onValueChanged: function() {
                            	var cameraR3 = camera.r3();
                                camera.r3([cameraR3[0], this.getValue(), cameraR3[2]]);
                                rangeNode.r3([cameraR3[0], this.getValue(), cameraR3[2]]);
                                getFrontImg(camera, rangeNode);
                            }
                        }
                      }
        ], 
        [0.1, 0.15]);
    

    控制面板通过 addRow 来添加控制元素,以上代码为添加摄像头绕着 y 轴进行旋转的控制,onValueChanged 在 slider 的数值改变的时候调用,此时通过 camera.r3() 获取当前摄像头的旋转参数, 由于是绕着 y 轴旋转所以 x 轴与 z 轴的角度是不变的,变的是 y 轴的旋转角度,所以通过 camera.r3([cameraR3[0], this.getValue(), cameraR3[2]]) 来调整摄像头的旋转角度以及通过 rangeNode.r3([cameraR3[0], this.getValue(), cameraR3[2]]) 来设置摄像头前方锥体的旋转角度,然后调用之前封装好的 getFrontImg 函数来获取此时旋转角度下面的实时图像信息。

    项目中通过 Panel 面板的配置参数 titleBackground: rgba(230, 230, 230, 0.4) 即可将标题背景设置为具有透明度的背景,其它类似的 titleColor, titleHeight 等标题参数都可以配置,通过 separatorColor,separatorWidth 等分割参数可以设置内部面板之间分割线的颜色,宽度等。最后面板通过 panel.setPositionRelativeTo(‘rightTop’) 将面板的位置设置成右上角,并且通过 document.body.appendChild(panel.getView()) 将面板最外层的 div 添加进页面中, panel.getView() 用来获取面板的最外层 dom 节点。

    具体初始化面板代码如下:

    function initPanel() {
        var panel = new ht.widget.Panel();
        var config = {
            title: "摄像头控制面板",
            titleBackground: 'rgba(230, 230, 230, 0.4)',
            titleColor: 'rgb(0, 0, 0)',
            titleHeight: 30,
            separatorColor: 'rgb(67, 175, 241)',
            separatorWidth: 1,
            exclusive: true,
            items: []
        };
        cameraArr.forEach(function(data, num){
            var camera = data['camera'];
            var rangeNode = data['rangeNode'];
            var formPane = new ht.widget.FormPane();
            initFormPane(formPane, camera, rangeNode);
            config.items.push({
                title: "摄像头" + (num + 1),
                titleBackground: 'rgba(230, 230, 230, 0.4)',
                titleColor: 'rgb(0, 0, 0)',
                titleHeight: 30,
                separatorColor: 'rgb(67, 175, 241)',
                separatorWidth: 1,
                content: formPane,
                flowLayout: true,
                contentHeight: 400,
                width: 250,
                expanded: num === 0
            });
        });
        panel.setConfig(config);
        panel.setPositionRelativeTo('rightTop');
        document.body.appendChild(panel.getView());
        window.addEventListener("resize", function() {
            panel.invalidate();
        });
    }
    

    在控制面板中可以调整摄像头的方向,摄像头监控的辐射范围,摄像头前方锥体的长度等等,并且摄像头的图像是实时生成,以下为运行截图:

    运行截图

    以下是本项目采用的 3D 场景结合 VR 技术实现的操作:

    VR 技术

    展开全文
  • 文章目录前言一、数据共享,直观形象高效二、...在这样一个纷繁复杂的环境下,3D可视化运维系统登场了。 举例如下:https://mr.laozicloud.com/case/details?id=1236970316308287488 各行各业都有一套符合自身行业特
  • 数据中心机房节能领域主要包括:建筑节能、动力与照明节能、空调与机房热管理节能、能耗监控与智能管理、新技术节能。 在建筑节能部分,应首先保证机房密封状态,其次应规划好需要制冷的空间,从细节着手,为数据...
  • Three.js实现3D机房效果

    2020-12-11 11:39:24
    3D机房系统是最近用户的需求,通过相关了解最后使用Three.js,也发现最近有东西可以写出来分享: webGL可以让我们在canvas上实现3D效果。而three.js是一款webGL框架,由于其易用性被广泛应用 Three.js是通过对WebGL...
  • 实现3D机房效果

    2018-06-29 16:44:01
    最美的机房3D效果展示。主要使用three.js创建3D机房模型。
  • 数据中心3D机房三维可视化管理项目,是ThingJS提供给广大用户的开源项目,用户可以通过借鉴或者使用这个开源项目完成属于自己的第一个3D机房三维可视化管理应用,同时,也可以在该项目中增加所需功能,如Echarts图表...
  • 随着现代企业信息建设的不断加快,为了确保机房安全、高效、可靠运行,运维管理工作显得愈发重要,而作为众多设备运行桥梁的综合布线系统目前仍然停留在传统的表格记录,CAD图纸存档的管理模式。每一个新建的机房...
  • 故在计算节点和管理平台版本高于(包含)2.5.6 时,引 入了由管理平台可视化操作机房切换、**机房回切、移除机房、修复机房、灾备演练等功能,可侧面提高机房操作的可靠性以及易用性**。 中心机房为当前主机房 中心...
  • 数据中心机房可视化能源管理系统解决方案
  • 针对电力调度中心机房可视化监管与自动化运维的需求,文中对现有的二维操控监管界面进行升级和改造,深入研究了三维的可视化交互技术。基于软件工程的理论,通过详尽的需求分析,明确系统所需实现的功能模块。根据...
  • 机房3D可视化,3D界面提供动态巡视功能,可任意指定巡视路线,设定巡视周期,自动进行实时的、平滑的巡视过程,巡视整个机房环境、机房设备、机柜列、IT设备等,动态展现机房各个部位的设备状况。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,107
精华内容 3,242
关键字:

可视化机房