• 【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();
    

    效果

    以下是结合真实模型的疏散路线效果

    如有描述不当之处,还请不吝赐教。

    作者:悠扬的牧笛
    地址:https://www.cnblogs.com/xhb-bky-blog/p/12521888.html
    声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    使用手机游戏的新闻推送
    win8.1 64位环境建设android开发环境
    LeetCode: Multiply Strings. Java
    Thread.join()分析方法
    字幕效果的幻灯片出现在网站上的图片
    JAVA技术交流群
    Android使得手机拍照功能的发展(源共享)
    领导基础课程
    Mysql开启远程连接方法
    mysql远程连接命令
  • 原文地址:https://www.cnblogs.com/xhb-bky-blog/p/12521888.html
Copyright © 2020-2023  润新知