1. 程式人生 > >【BIM】BIMFACE中建立疏散效果

【BIM】BIMFACE中建立疏散效果

背景

在BIM運維中,消防疏散是不可或缺的一環,當發生火警的時候,觸發煙感器發生報警,同時啟動消防疏散,指導現場工作人員進行疏散,及時準確地顯示出疏散路線對爭取疏散時間尤為重要。我將介紹如何在bimface中建立消防疏散指示動畫效果。

思路

第一種方式就是通過bimface自帶的材質物件,結合requestAnimationFrame函式實現,具體地址見官網的水流效果。這種方式存在弊端,首先程式碼量相對來說比較大,要配置各種物件的引數;其次對構件有強依賴性,也就是說這種方式是對構件進行材質重寫來實現的;此外這種方式的貼圖是通過UV貼圖實現,貼圖縮放比例不好確定,需要摸索試探地確定比較合適的引數,第二種方式是直接通過threejs來實現,相對於第一種方式而言,無需太多的程式碼,直奔主題,最重要的是不依賴構件(實際上是自己建立了Mesh

),也就是說沒有構件同樣可以實現上述效果,最重要的是不用再摸著石頭貼圖了,自己能夠掌握貼圖的規律。本文中採用第二種方式來實現疏散效果,其實思路很簡單,無非是建立Mesh,然後給Mesh貼上帶箭頭的圖片,完成貼圖後動態地修改貼圖的偏移量(offset),就實現了箭頭動畫效果。

實踐

首先來製作材質,因為路線由若干個PlaneBufferGeometry組成,所以每一個都要進行貼圖操作,其實除了圖片在PlaneBufferGeometry上的分佈個數不一致,其他的引數都是一致的,所以要結合圖片的大小和PlaneBufferGeometry的長度來動態計算每個PlaneBufferGeometry上材質需要重複的次數。將建立的材質放入集合中是為了後續在執行動畫時,可以針對每一個材質進行偏移量的修改,程式碼如下:

//宣告儲存材質的集合
var textureCollection = [];
function generateMaterial(repeat) {
    var basicMaterial = new THREE.MeshBasicMaterial();
    texture = new THREE.TextureLoader().load('images/icon_arrow_right_pow.png', function (map) {
        basicMaterial.map = map;
        basicMaterial.wireframe = false;
        basicMaterial.needsUpdate = true;
        basicMaterial.transparent = true;
        basicMaterial.side = THREE.DoubleSide;
    });
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.x = repeat;
    textureCollection.push(texture);
    return basicMaterial;
}

有了材質,還需要建立若干個Mesh,因為疏散路線是由一個一個的長條矩形組成,所以選擇用平面PlaneBufferGeometry來製作,材質使用箭頭圖片進行貼圖。程式碼如下:


/**
 * @param {若干Mesh的集合,每個Mesh結構如下} planeArray
 * 
 * @param {構件最小點世界座標} min_position 
 * @param {構件最大點世界座標} max_position 
 * @param {構件方向,上下左右以此對應(1,-1,2,0)} direction 
 */
function loadPlane(planeArray) {
    // 標準寬度
    const statndardWidth = 500;
    // 用於計算標準圖片重複個數
    const statndardRepeat = 600;
    // 指定預設角度
    const rotate = Math.PI / 2;

    var planeGroup = new THREE.Group();
    // 思路一:僅用最大點進行定位(目前採用)
    // 思路二:用最大點和最小點進行定位
    for (let k = 0, l = planeArray.length; k < l; k++) {
        let l = position_x = position_y = 0;
        //區分橫向和縱向
        if (planeArray[k].direction === 1 || planeArray[k].direction === -1) {
            l = Math.floor(planeArray[k].max_position.y - planeArray[k].min_position.y);
            position_x = planeArray[k].max_position.x - (statndardWidth / 2);
            position_y = planeArray[k].max_position.y - (l / 2);

        } else {
            l = Math.floor(planeArray[k].max_position.x - planeArray[k].min_position.x);
            position_x = planeArray[k].max_position.x - (l / 2);
            position_y = planeArray[k].max_position.y - (statndardWidth / 2);
        }

        let _material = generateMaterial(Math.floor(l / statndardRepeat));
        let planeGeometry = new THREE.PlaneBufferGeometry(l, statndardWidth, 100, 50);
        let plane = new THREE.Mesh(planeGeometry, _material);
        plane.position.x = position_x;
        plane.position.y = position_y;
        plane.position.z = planeArray[k].max_position.z + 10;
        plane.rotation.z = rotate * planeArray[k].direction;
        planeGroup.add(plane);
    }
    viewer.addExternalObject("planeGroup", planeGroup);
    viewer.render();
}

目前形狀和材質都已經建立完成,整個場景還是靜態的,由箭頭組成的平面形狀集合,下一步是讓這些箭頭跑起來,思路就是在渲染的時候動態修改材質的offset,程式碼如下:

function animate() {
    animationId = requestAnimationFrame(animate);
    for (let m = 0, len = textureCollection.length; m < len; m++) {
        textureCollection[m].offset.x += 0.005;
    }
    viewer.render();
}

使用方式,只需要將mesh對應的包圍盒最大點和最小點(用於確定位置)以及箭頭方向(用於確定箭頭流向)的引數放在陣列中傳入loadPlane函式,然後呼叫animate函式即可實現疏散效果,程式碼如下:

let planeArray = [];
const UP = 1;
const DOWN = -1;
const LEFT = 2;
const RIGHT = 0;

let a = { min_position: { x: -10432.83984375, y: 20233.87109375, z: 15 }, max_position: { x: -9932.83984375, y: 26744.16796875, z: 40 }, direction: UP };
let b = { min_position: { x: -14117.83984375, y: 28943.8671875, z: 15 }, max_position: { x: -12812.83984375, y: 29443.8671875, z: 50 }, direction: RIGHT };
let c = { min_position: { x: -7591.01171875, y: 27244.16796875, z: 15 }, max_position: { x: -7091.01171875, y: 33333.8671875, z: 20 }, direction: UP };

planeArray.push(a);
planeArray.push(b);
planeArray.push(c);

loadPlane(planeArray);
animate();

效果

以下是結合真實模型的疏散路線效果

如有描述不當之處,還請不吝賜教。

作者:[悠揚的牧笛](http://www.cnblogs.com/xhb-bky-blog) 地址:[https://www.cnblogs.com/xhb-bky-blog/p/12521888.html](https://www.cnblogs.com/xhb-bky-blog/p/12521888.html) 宣告:本部落格原創文字只代表本人工作中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未授權貼子請以現狀保留,轉載時必須保留此段宣告,且在文章頁面明顯位置給出原文連