使用gltf模型做一个VR地图

做一个类似于https://my.matterportvr.cn/show/?m=WsQvZoxSg5d这样的,可以点击选择进入某某房间查看和观看楼层平面图以及楼层选择器的网页:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AR导航</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        body{
            overflow: hidden;
        }
       .btn-container{
            position: absolute;
            left: 10px;
            top: 10px; 
            z-index: 10;
            width: 100px;
            display: flex;
            justify-content: space-between;
        
        }
        .btn-container img{
            height: 40px;
        }
        ul{
            list-style: none;
        }
        li{
            text-align: center;
            padding: 5px 0px;
        }
        li:hover{
            background-color: rgba(0,0,0,0.3);
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="btn-container">
        <img class="reset-btn" title="查看楼层平面图" @click='reset' src="./imgs/map.png" alt="">
        <div class="layer-box">
            <img class="layer-btn" title="楼层选择器" @click='toggleLayerShow' src="./imgs/layer.png" alt="">
            <ul v-if = 'layerShow'>
                <li v-for='(item,index) in layerData' v-bind:data-key='item.key' @click='selectLayer'>{{item.name}}</li>
            </ul>
        </div>
    </div>
	<div id="container"></div>
</body>
<script src="js/vue.js"></script>
<script src="js/three.js"></script> 
<script src="js/loaders/GLTFLoader.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/renderers/CSS2DRenderer.js"></script>
<script src="js/libs/Tween.js"></script>
<script>
    (function(){
        const gltfLoader = new GLTFLoader();
        const modelUrl = 'https://houtaicdn.alva.com.cn/medias/resources/wechat/XiamenLieshi/model/GLTF3/XM.gltf';
        let scene,camera,renderer,controls,model;
        let sceneName = 'global';

        const origin = new THREE.Vector3(0,0,5), direction = new THREE.Vector3(0,0,5).normalize();
        let mouse = new THREE.Vector2(), raycaster = new THREE.Raycaster(origin, direction);

        init();
        // addHelper();

        function init(){
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight, 0.1,1000);
            camera.position.z = 5;

            initControls();
            // addResetBtn();
            gltfLoader.load(modelUrl,function(gltf){
                model = gltf.scene;
                // model.position.set(0,-30,150);
                model.scale.set(3,3,3);
                model.rotation.set(1.5,0,0);
                scene.add(model);

                initLight();
            });

            renderer = new THREE.WebGLRenderer({
                antialias: true,
                alpha: true,
                preserveDrawingBuffer: true
            });
            renderer.setSize(window.innerWidth,window.innerHeight);
            document.body.appendChild(renderer.domElement);
            animate()
        }

        document.body.addEventListener('mousedown',onDown,false);
        function onDown(event){
            event.preventDefault();
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(mouse, camera);
            var intersects = raycaster.intersectObjects(model.children);
            if (intersects.length > 0 && sceneName === 'global') {// 如果点击到了某个房间,则进入此房间查看
                const name = intersects[0].object.name;
                console.log(name)
                goPart(name);
            }
        }

        function goPart(name){
            if (sceneName === 'Ani') return;
            sceneName = 'Ani';
            var sName = '';
            var tweenP = new TWEEN.Tween(model.position);// TWEEN过渡动画
            var tweenS = new TWEEN.Tween(model.scale);
            var tweenR = new TWEEN.Tween(model.rotation);
            tweenS.to(new THREE.Vector3(300,300,300),3000);
            tweenR.to(new THREE.Vector3(0,0,0), 1000);
            
            tweenP.easing(TWEEN.Easing.Quadratic.InOut);
            tweenS.easing(TWEEN.Easing.Quadratic.InOut);
            tweenR.easing(TWEEN.Easing.Quadratic.InOut);

            controls.reset();

            switch(name){
                    case '房间1':// 正中
                        sName = 'center';
                        tweenP.to(new THREE.Vector3(0,40,0),3000);
                        break;
                    case '房间2':// 中左
                        sName = 'center-left';
                        tweenP.to(new THREE.Vector3(170,20,0),3000);
                        break;
                    case '房间3':// 中右
                        sName = 'center-right';
                        tweenP.to(new THREE.Vector3(-140,-30,0),3000);
                        break;
                    case '房间4':// 上左
                        sName = 'top-left';
                        tweenP.to(new THREE.Vector3(80,-30,150),3000);
                        break;
                    case '房间5':// 上右
                        name = 'top-right';
                        tweenP.to(new THREE.Vector3(-80,-30,150),3000);
                        break;
                    case '房间6':// 下
                        sName = 'bottom';
                        tweenP.to(new THREE.Vector3(0,0,-150),3000);
                        break;
                }

            // tweenP.delay(2000);
            tweenP.start();
            tweenS.start();
            tweenR.start();
            
            tweenP.onComplete(() => {
                sceneName = sName;
            })

        }

        
        function initLight(){
            var aLight = new THREE.AmbientLight(0xffffff,0.2);
            scene.add(aLight)
            var dLight1 = new THREE.PointLight(0xffffff,1,100);  
            dLight1.position.set(0,60,0);
            dLight1.target = model;
            scene.add(dLight1);
            var dLight2 = new THREE.PointLight(0xffffff,1,300);  
            dLight2.position.set(170,40,0);
            dLight2.target = model;
            var dLight3 = new THREE.PointLight(0xffffff,1,300);  
            dLight3.position.set(-140,-10,0);
            dLight3.target = model;
            scene.add(dLight3);
            var dLight4 = new THREE.PointLight(0xffffff,1,300);  
            dLight4.position.set(80,-10,150);
            dLight4.target = model;
            scene.add(dLight4);
            var dLight5 = new THREE.PointLight(0xffffff,1,300);  
            dLight5.position.set(0,20,-150);
            dLight5.target = model;
            scene.add(dLight5);
        }

        function animate(){
            requestAnimationFrame(animate);
            renderer.render(scene,camera);
            TWEEN.update();
        }

        function initControls(){
            controls = new THREE.OrbitControls(camera)
            controls.enableZoom = true
            //controls.autoRotate = true;
            controls.minDistance = 3;
            controls.maxDistance = 10;
            
            controls.enablePan = false;
        }

        function addHelper(){
            // var dir = new THREE.Vector3( 1, 2, 0 );
            // dir.normalize();
            // var origin = new THREE.Vector3( 0, 0, 0 );
            // var length = 1;
            // var hex = 0xffff00;
            // var arrowHelper = new THREE.ArrowHelper( dir, origin, length, hex );
            // scene.add( arrowHelper );

            // 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
            var axesHelper = new THREE.AxesHelper(250);
            scene.add(axesHelper);
        }
    
        function addResetBtn(){
            let labelRenderer = new CSS2DRenderer('img');
            labelRenderer.setSize( 60, 40 );
            // labelRenderer.domElement.style.pointerEvents = 'none';// 禁用事件

            labelRenderer.domElement.style.position = 'absolute';
            labelRenderer.domElement.style.top = '10px';
            labelRenderer.domElement.style.left = '10px';
            labelRenderer.domElement.src = './imgs/map.png';
            labelRenderer.domElement.alt = '平面图';
            labelRenderer.domElement.title = '平面图';

            labelRenderer.domElement.addEventListener('click',reset,false);
            labelRenderer.render( scene, camera );

            document.getElementById( 'container' ).appendChild( labelRenderer.domElement );
        }


        
        var vm = new Vue({
            el: '.btn-container',
            data: {
                layerData:[
                    {name: '全部', key: '0'},
                    {name: '一楼', key: '1'},
                    {name: '二楼', key: '2'},
                ],
                layerShow: false
            },
            methods:{
                toggleLayerShow(){
                    this.layerShow = !this.layerShow;
                },
                selectLayer(e){
                    this.layerShow = !this.layerShow;
                    const { key } = e.srcElement.dataset;
                    camera.layers.mask = Number(key);//  修改显示的楼层
                },
                reset(){// 查看平面图
                    if (sceneName === 'Ani') return;
                    sceneName = 'Ani';
                    // model.position.set(0,0,0);
                    // model.scale.set(3,3,3);
                    // model.rotation.set(1.5,0,0);
                    controls.reset();
                    var tweenP = new TWEEN.Tween(model.position);
                    tweenP.to(new THREE.Vector3(0,0,0), 2000);
                    var tweenR = new TWEEN.Tween(model.rotation);
                    tweenR.to(new THREE.Vector3(1.5,0,0), 2000);
                    var tweenS = new TWEEN.Tween(model.scale);
                    tweenS.to(new THREE.Vector3(3,3,3), 2000);

                    tweenP.easing(TWEEN.Easing.Quadratic.InOut);
                    tweenS.easing(TWEEN.Easing.Quadratic.InOut);
                    tweenR.easing(TWEEN.Easing.Quadratic.InOut);

                    tweenP.start(); 
                    tweenR.start(); 
                    tweenS.start();
                    tweenP.onComplete(() => {   
                        sceneName = 'global';
                    })
                }
            }
        });
    })()
</script>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值