1. 程式人生 > >基於WebGL(ThingJS)的平面圖導航,室內導航,3D聚焦 (二)

基於WebGL(ThingJS)的平面圖導航,室內導航,3D聚焦 (二)

title init aps 能夠 繼承 posit children inverse total

前言

基於WebGL架構的3D可視化平臺—平面圖導航(一)中已經完成了iframe面板與我們的3D場景的簡單交互,下面我們繼續完善並給iframe頁加上鼠標懸停事件讓iframe頁的img標簽和我們場景中的obj一起動起來。

實現

第一步,還是使用之前的場景接著上次的繼續,先編寫iframe頁。給每一個img標簽都加上onmouseover、onmouseout 事件。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
      	.total_image {
        	margin : 20px;
        }
        .total_image img{
            cursor: pointer;
            transition: all 0.6s;
            width: 50px;
        }
        .total_image img:hover{
            transform: scale(1.5);
            position:relative;
            z-index:100;
        }
    </style>
</head>

<body>
<div class="total_image" style="width: 500px;height: 280px;background-size: 100% auto">
    <img class="model_imag" src="發電室1.jpg" style="float: left;display: block;width: 85px;height: 84px" 
			onclick="onClick(‘PowerGenerationGroup_01‘,‘viewPoint_1‘)" onmouseover="onMouseOver(‘PowerGenerationGroup_01‘,‘viewPoint_1‘)" onmouseout="onMouseOut(‘PowerGenerationGroup_01‘)">
              
    <img class="model_imag" src="發電室2.jpg" style="float: left;display: block;width: 78px;height: 84px" 
			onclick="onClick(‘PowerGenerationGroup_02‘,‘viewPoint_2‘)" onmouseover="onMouseOver(‘PowerGenerationGroup_02‘,‘viewPoint_2‘)" onmouseout="onMouseOut(‘PowerGenerationGroup_02‘)">
              
    <img class="model_imag" src="發電室3.jpg" style="float: left;display: block;width:170px;height: 84px" 
			onclick="onClick(‘PowerGenerationGroup_03‘,‘viewPoint_3‘)" onmouseover="onMouseOver(‘PowerGenerationGroup_03‘,‘viewPoint_3‘)" onmouseout="onMouseOut(‘PowerGenerationGroup_03‘)">
              
    <img class="model_imag" src="發電室4.jpg" style="float: left;display: block;width:167px;height: 84px" 
			onclick="onClick(‘PowerGenerationGroup_04‘,‘viewPoint_4‘)" onmouseover="onMouseOver(‘PowerGenerationGroup_04‘,‘viewPoint_4‘)" onmouseout="onMouseOut(‘PowerGenerationGroup_04‘)">
              
    <div style="display: block;float: left;width: 100px;height: 145px;background-color:white">
        <img class="model_imag" src="辦公室1.jpg" style="float: left;display: block;width:100px;height: 60px" 
			onclick="onClick(‘Office‘,‘viewPoint_5‘)" onmouseover="onMouseOver(‘Office‘,‘viewPoint_5‘)" onmouseout="onMouseOut(‘Office‘)">
        <img class="model_imag" src="返回.png" style="float: left;display: block;width:100px;height: 80px" onclick="initViewPoint()">
    </div>

    <img class="model_imag" src="發電室5.jpg" style="float: right;display: block;width:123px" 
			onclick="onClick(‘PowerGenerationGroup_05‘,‘viewPoint_8‘)" onmouseover="onMouseOver(‘PowerGenerationGroup_05‘,‘viewPoint_8‘)" onmouseout="onMouseOut(‘PowerGenerationGroup_05‘)"> 
              
    <img class="model_imag" src="會議室1.jpg" style="float: left;display: block;width: 138px;height: 145px"   
			onclick="onClick(‘BoardRoom_01‘,‘viewPoint_6‘)" onmouseover="onMouseOver(‘BoardRoom_01‘,‘viewPoint_6‘)" onmouseout="onMouseOut(‘BoardRoom_01‘)">
              
    <img class="model_imag" src="會議室2.jpg" style="float: left;display: block;width: 138px;height: 145px"   
			onclick="onClick(‘BoardRoom_02‘,‘viewPoint_7‘)" onmouseover="onMouseOver(‘BoardRoom_02‘,‘viewPoint_7‘)" onmouseout="onMouseOut(‘BoardRoom_02‘)"> 
</div>

<script>
    function onClick(viewPoint,target){
        window.parent.onClick(viewPoint,target);
    }
	
	function onMouseOver(targetObj,viewPoint){
    	window.parent.onMouseOver(targetObj,viewPoint);
    }
  	function onMouseOut(targetObj){
        window.parent.onMouseOut(targetObj);
    }
	function initViewPoint(){
        window.parent.initViewPoint();
    }
	
</script>
</body>
</html>

  技術分享圖片

第二步,房間裏的物體不要要讓他“飛起來”,還要給他加一個“底座”。這裏叫他SurveillanceCamera類,在自己編寫類的時候一定要註意,想要當前類生效一定要繼承THING.Thing,並且THING.factory.registerClass(‘ClassName’, ClassName);

class SurveillanceCamera extends THING.Thing {
    constructor(app) {
        super(app);
        this.app = app;
        this.isFrustum = true;
        this.opacity = 1;
        this.color = 0xff00ff;
        this.vertices = [];
        this.near = 0.1;
        this.camera = null;
        this.node = new THREE.Object3D();
        this._frustum = new THREE.Frustum();
        this._projScreenMatrix = new THREE.Matrix4();

    }

    setup(param) {
        super.setup(param);
        this.fov = param[‘fov‘];
        this.aspect = param[‘aspect‘];
        this.far = param[‘far‘];
        this.alpha = param[‘alpha‘];
        this.lineAlpha = param[‘lineAlpha‘];
        this.setupComplete(param);
    }

    setupComplete(param) {
        super.setupComplete(param);
        this.build();
    }

    build() {
        if (this.node.children.length > 0) {
            this.node.children = [];
        }

        if (this.camera != null) {
            this.camera = null;
        }

        var h = this.far * Math.tan(this.fov * 0.5 * 0.017453293);
        var w = this.aspect * h;

        var geometry = new THREE.Geometry();
        this.vertices = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(w, -h, -this.far), new THREE.Vector3(w, h, -this.far), new THREE.Vector3(-w, h, -this.far), new THREE.Vector3(-w, -h, -this.far)];
        var faces = [new THREE.Face3(0, 1, 2), new THREE.Face3(0, 2, 3), new THREE.Face3(0, 3, 4), new THREE.Face3(0, 4, 1), new THREE.Face3(3, 4, 1), new THREE.Face3(3, 1, 2)];
        geometry.vertices = this.vertices;

        var line_mat = new THREE.LineBasicMaterial({
            color: "#b4f5f8",
            opacity: this.lineAlpha || 0.5,
        })

        var texture = THREE.ImageUtils.loadTexture("images/light2.png");
        texture.wrapS = THREE.RepeatWrapping;
        texture.wrapT = THREE.RepeatWrapping;
        var frustum_mat = new THREE.MeshBasicMaterial({
            color: "#0aa5ff",
            opacity: this.alpha || 0.5,
            transparent: true,
            side: THREE.DoubleSide,
        });
        var line_mesh = new THREE.Line(geometry, line_mat);

        var frustum_mesh = new THREE.Mesh(geometry, frustum_mat);
        geometry.faces = faces;
        this.node.add(frustum_mesh, line_mesh);

        this.camera = new THREE.PerspectiveCamera(this.fov, this.aspect, this.near, this.far);
        this.camera.position.set(this.position[0], this.position[1], this.position[2]);
        this.camera.rotation.copy(this.node.rotation);

        this.camera.updateMatrixWorld(true);
        this._updateFrustum();
    }

    setPosition() {
        this.camera.position.set(this.position[0], this.position[1], this.position[2]);
        this.camera.updateMatrixWorld(true);
        this._updateFrustum();
    }

    _updateFrustum() {
        if (this.camera) {
            this._projScreenMatrix.multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse);
            this._frustum.setFromMatrix(this._projScreenMatrix);
        }
    }

    intersectsObject(object) {
        this._updateFrustum();
        return this._frustum.intersectsObject(object);
    }

    intersectsBox(box) {
        this._updateFrustum();
        return this._frustum.intersectsBox(box);
    }

    intersectsSphere(sphere) {
        this._updateFrustum();
        return this._frustum.intersectsSphere(sphere);
    }

    intersectsSprite(sprite) {
        this._updateFrustum();
        return this._frustum.intersectsSprite(sprite);
    }
}

THING.factory.registerClass(‘SurveillanceCamera‘, SurveillanceCamera);

  技術分享圖片

第三步,鼠標懸浮事件和鼠標離開事件,這裏我們使用了之前創建的SurveillanceCamera類為obj加上了一個“底座”。

//鼠標懸浮事件
function onMouseOver(targetObj,viewPoint) {
    if (currentModule != null)
        return;
    overModule = app.query(targetObj)[0];
    overModule.style.boundingBox = true;
    overModule.moveTo({
        "offset": [0, 6, 0],
        "time": 80,
    });
    sCamera = app.create({
        type: ‘SurveillanceCamera‘,
        name: ‘SurveillanceCamera_‘,
        position:app.query(viewPoint)[0].position,
        fov: 65,
        aspect: 1.3,
        far: 6,
    });
    sCamera.angleX = 90;
    sCamera.style.opacity = 0.1;
}
//鼠標離開事件
function onMouseOut(targetObj) {
    if (currentModule != null)
        return;
    if (sCamera) {
        sCamera.destroy();
        sCamera = null;
    }
    outModule = overModule;
    outModule.style.boundingBox = false;
    outModule.stopMoving();
    outModule.position = [0, 0, 0];
    outModule = null;
}

  技術分享圖片

演示地址:http://www.thingjs.com/guide/sampleindex.html?name=/uploads/wechat/S2Vyd2lu/Demo_平面圖導航.js

總結

利用iframe與ThingJS進行交互完成了平面圖導航功能,通過自制的HTML界面,嵌入ThingJS的面板中,形成一個可自定義的導航界面,通過偏移實現相應的視覺效果。
制作一個視錐,達到投放影像的效果,這裏運用面向對象的方式是為了,能夠更快捷的創建視錐,起到復用的作用。
在制作過程中,將物體懸浮的過程時出現了問題,發現如果快速的操作鼠標,物體不會達到預期的視覺效果,例如,鼠標快速的在兩個導航圖之間切換時,對應的兩個物體會不斷的上升,盡管將上升與還原的速度加快,也依然無法解決問題。最後解決的辦法是:新添加一個變量,將上一次懸浮的物體記錄下來,就是文中的 outModule,通過對 outModule 單獨操作來解決影響問題。

基於WebGL(ThingJS)的平面圖導航,室內導航,3D聚焦 (二)