Heim  >  Artikel  >  Web-Frontend  >  HTML5-WebGL-Druck 3D-Computerraum

HTML5-WebGL-Druck 3D-Computerraum

php中世界最好的语言
php中世界最好的语言Original
2018-03-20 13:24:351937Durchsuche

Dieses Mal präsentiere ich Ihnen den HTML5-WebGL-Druck-3D-Computerraum. Was sind die Vorsichtsmaßnahmen für den HTML5-WebGL-Druck-3D-Computerraum?

Vorwort

Mit WebGL gerenderte 3D-Computerräume sind nichts Neues. Der Hauptzweck dieses Artikels besteht darin, das Auge zu erklären und das Problem der Mitte zu lösen Nachdem ich eine Weile darüber nachgedacht hatte, kam ich schließlich zu dem Schluss, dass dieses Beispiel meinen Anforderungen am besten entsprach, also habe ich es als Aufzeichnung verwendet.

Renderings

Die Demo dieses 3D-Computerraums ist ziemlich gut, hübsch und die grundlegenden Interaktionen sind zufriedenstellend und sehen Sie, wie es geht.

Codegenerierung

Klassen definieren

Öffnen Sie zunächst nacheinander die entsprechenden js-Pfade, die aus index.html aufgerufen werden , server.js verfügt über eine angepasste Editor.Server-Klasse, die durch die von HT gekapselte Funktion ht.Default.def erstellt wurde (beachten Sie, dass der Editor vor dem erstellten Klassennamen Editor.Server nicht durch E ersetzt werden kann):

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);
    }
});

Erstellen Sie die Editor.Server-Klasse

Diese Klasse kann einen ht.Node-Knoten erstellen und die Farbe und die vordere Textur des Knotens festlegen:

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 //设置节点正面的图片
    });
};

Auf diese Weise kann ich direkt ein neues Serverkomponentenobjekt erstellen, in dem ich die Serverkomponente erstellen muss, und ich kann setHost und andere oben deklarierte Funktionen direkt aufrufen, die wir bald verwenden werden.

Als nächstes erstellen Sie die Editor.Cabinet-Schrankklasse. Die Methode ähnelt der Definitionsmethode der Editor.Server-Klasse oben:

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 坐标
    }
});

Erstellen Sie die Editor.Cabinet-Klasse

Diese Klasse ist relativ komplexer als die vorherige Serverkomponentenklasse Editor.Server. Diese Klasse erstellt einen Schrankkörper, eine Schranktür und Serverkomponenten im Schrank:

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 节点
    });
};

Das Einzige, was im obigen Code nicht erwähnt wird, ist die Funktion Editor.randomList. Diese Funktion ist in der Datei global.js deklariert und wie folgt deklariert:

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;
    }
};

Okay, Klassen für jede Ein Teil der Szene ist erstellt. Fertig, dann sollten wir die Szene erstellen und diese Grundelemente darin anhäufen!

Szenenerstellung

Wenn Sie damit vertraut sind, sollten Sie wissen, dass die Verwendung von HT zum Erstellen einer 3D-Szene nur eine neue 3D-Komponente erfordert und dann die Szene hinzugefügt werden muss über die addToDOM-Funktion:

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

Die Datei main.js übernimmt hauptsächlich die Generierung und Entladung einiger notwendiger Elemente in der 3D-Szene, wie z. B. Wände, Böden, Türen, Klimaanlagen und alle Schränke und der sehr wichtige interaktive Teil.

Ich werde den Code für die Erstellung von Wänden, Böden, Türen, Klimaanlagen und Schränken nicht veröffentlichen. Wenn Sie interessiert sind, überprüfen Sie bitte den Code selbst. Hier geht es hauptsächlich um das Doppelklicken auf den Schrank und alle anderen Objekt im Zusammenhang mit dem Schrank (Schranktür, Serverausrüstung), die Sichtlinie der Kamera in 3D bewegt sich zu einer Position vor dem doppelt angeklickten Schrank, und diese Bewegung ist sehr reibungslos. Meine bisherigen Fähigkeiten waren daher nicht gut Ich habe lange über diesen Teil nachgedacht und schließlich auf die Implementierung dieser Demo-Methode verwiesen.

Um Auge und Mitte wiederholt festlegen zu können, wird der Inhalt, der dem Festlegen dieser beiden Parameter entspricht, in die Methoden setEye und setCenter gekapselt. Die Methode setCenter ähnelt der Methode setEye und wird hier nicht wiederholt :

// 设置眼睛位置
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
            ]);
        }
    });
};

Nur ​​weil ich die setCenter-Funktion nicht wiederholt deklariert habe, heißt das nicht, dass diese Funktion nicht wichtig ist. Im Gegenteil, diese Funktion spielt eine entscheidende Rolle bei der Bewegung des „Sehvermögens“. Die obige setEye-Funktion entspricht dem Wunsch, vor meiner Zielposition zu gehen (zumindest ist dies der Zweck, wenn ich sie definiere), und die Definition von sCenter besteht darin, meinen Blick auf die Position des Ziels zu richten (z. B , ich kann an meiner aktuellen Position stehen und auf das Objekt rechts hinter mir schauen, oder ich kann nach rechts gehen. Gehen Sie nach hinten und stellen Sie sich vor das Objekt, um es zu betrachten. Das ist sehr wichtig, genießen Sie es bitte Es.

Das Doppelklick-Ereignis ist einfach. Hören Sie sich einfach das HT-gekapselte Ereignis an, bestimmen Sie den Ereignistyp und ergreifen Sie entsprechende Aktionen:

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 眼睛要移向的位置
});

Obere Navigationsleiste

一开始看到这个例子的时候我在想,这人好厉害,我用 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 表单组件底层 p 添加进 body 中
    window.addEventListener('resize', function() {//窗口大小变化事件监听
        E.top.iv();//更新 form 表单的底层 p 
    });
});

这里说明一下 addToDOM 函数,对于了解 HT 的机制非常重要。HT 的组件一般都会嵌入 BorderPane、SplitView 和 TabView 等容器中使用,而最外层的 HT 组件则需要用户手工将 getView() 返回的底层 p 元素添加到页面的 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); //将场景的底层 p 添加进 body 中           
    style.left = '0';//HT 默认将所有的组件底层p的position设置为absolute
    style.right = '0';
    style.top = '0';
    style.bottom = '0';      
    window.addEventListener('resize', function () { self.iv(); }, false); //窗口大小变化监听事件,通知组件变化更新          
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

text-align如何实现两端对齐

Mac系统里MySQL重置Root密码

Das obige ist der detaillierte Inhalt vonHTML5-WebGL-Druck 3D-Computerraum. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn