今回は 3D コンピューター室の HTML5 WebGL 印刷についてお届けします。 3D コンピューター室の HTML5 WebGL 印刷の注意点 について、実際の事例を見てみましょう。
はじめに
WebGL でレンダリングされた 3D コンピューター ルームは、今では何も目新しいものではありません。この記事の主な目的は、たまたまプロジェクトで使用されている 3D コンピューター ルームの目と中心の問題を説明することです。しばらく考えた結果、この例が私の要件に最も適していると感じたので、記録として使用しました。
レンダリング
この 3D コンピューター ルームのデモは非常に優れており、美しく、基本的なインタラクションも満足のいくものです。実装方法を見てみましょう。
コード生成
定義クラス
まずindex.htmlで呼ばれるjsパスから該当するjsを一つずつ開き、server.jsでEditor.Serverクラスをカスタマイズし、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 //设置节点正面的图片 }); };
このようにして、サーバー コンポーネントを作成する必要がある場所に新しいサーバー コンポーネント オブジェクトを直接作成でき、上で宣言した 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 シーンを作成するには、新しい 3D コンポーネントのみが必要であり、addToDOM 関数を使用してそのシーンをボディに追加するだけであることを知っているはずです:
var g3d = E.main = new ht.graph3d.Graph3dView(); //3d 场景
main.jsファイル 私たちが主に行うことは、壁、床、ドア、エアコン、すべてのキャビネットなどの 3D シーン内のいくつかの必要な要素と、非常に重要なインタラクティブ パーツの位置を生成および放出することです。
壁、床、ドア、エアコン、キャビネットの作成コードは掲載しませんので、興味がある方はご自身でコードを確認してください。ここでは主にキャビネットとそれに関連するオブジェクトのダブルクリックについて説明します。キャビネット(キャビネットのドア、サーバー機器) すると、ダブルクリックしたキャビネットの前の一定の位置にカメラの視線が3Dで移動するのですが、この動きが非常にスムーズでした。私のスキルが完璧ではなかったので、これについて考えました。の部分を長々と説明してきましたが、最後に今回のDemoの実装方法について言及しました。
eye と center を繰り返し設定できるようにするために、これら 2 つのパラメータの設定に対応するコンテンツは setEye メソッドと setCenter メソッドにカプセル化されています。setCenter メソッドは setEye メソッドに似ているため、ここでは繰り返しません。
setCenter 関数が重要ではないことを繰り返し宣言しませんでした。逆に、この関数は「視線」を動かすプロセスにおいて決定的な役割を果たします。 sCenter の定義は、ターゲットの位置の前にあり (少なくとも、これを定義するときの目的です。)、sCenter の定義は、ターゲットの位置に視線を移動することです (たとえば、現在の位置に立って、次の場所を見ることができます)。右側の後ろにある物体を見てください。または、右側の後ろに行って物体の前に立ってそれを見ることもできます)、これは非常に重要です。味わってください。 ダブルクリック イベントは単純で、HT でカプセル化されたイベントをリッスンし、イベント タイプを判断し、対応するアクションを実行するだけです。一开始看到这个例子的时候我在想,这人好厉害,我用 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中文网其它相关文章!
推荐阅读:
以上がHTML5 WebGL印刷3Dコンピュータ室の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。