three.js中的事件


以上一篇入門篇為例來簡單的設置下3d模型當中的交互事件,上一篇我們已經完成了在3d頁面中添加了一個紅色球,下面我們給這個球一個點擊事件讓它Y軸位置上升,再設置一個鼠標移入到球上時讓其變色。

1.其實three.js當中沒有事件可以直接選中物體的,我們需要監聽window對象來完成與3d頁面的交互,通過使用到three.js當中RayCaster對象,用於在三維空間中進行鼠標拾取,原理是:相機與鼠標所在的設備坐標之間的連線與哪些物體相交。相交的物體離屏幕越近的越靠前,所以第一個物體就是我們選中的對象。

第一步:給window對象添加點擊事件監聽器;

    window.addEventListener('mousedown', mouseDownFuc);

第二步:在事件監聽函數里拾取到點擊的對象集合;

    function mouseDownFuc(){
        let raycaster = new THREE.Raycaster();//創建光線投射對象
        let mouse = new THREE.Vector2();//創建二維平面
        let intersectsObjArr = getSelsectOBj(mouse,raycaster, e);//通過封裝的getSelsectOBj函數獲取鼠標選中對象集合,e是點擊事件對象
    }     
    //獲取事件操作對象
    function getSelsectOBj(mouse,raycaster, e) {
        //將html坐標系轉化為webgl坐標系,並確定鼠標點擊位置
        mouse.x =  e.clientX / renderer.domElement.clientWidth*2-1;
        mouse.y =  -(e.clientY / renderer.domElement.clientHeight*2)+1;
        raycaster.setFromCamera(mouse,camera);//以camera為z坐標,確定所點擊物體的3D空間位置
        let intersects = raycaster.intersectObjects(scene.children, true);//確定所點擊位置上的物體數量集合
        return intersects;//返回連線經過的物體集合
    }

第三步:判斷intersectsObjArr集合長度不為零,確認我們鼠標點擊的地方有物體,如果有物體那么intersectsObjArr[0]就是我們選中的對象,通過頁面console.log(intersectsObjArr[0])發現intersectsObjArr[0]包含了相交點的許多信息,而我們只需要交點的對象,所以我們需要取到intersectsObjArr[0].object對象;然后我們還需要進行一次判斷當前對象就是我們點擊的對象,在這里我們還得回到創建物體時給它的name屬性一個值進行區分物體。最后給它position屬性值的Y軸坐標設為50;

        myBall.name = 'redBall';//創建物體時給它name屬性一個名稱
        if(intersectsObjArr.length > 0){
            if(intersectsObjArr[0].object.name == 'redBall'){
                intersectsObjArr[0].object.position.y = 50;
            }
        }

以上就是我們完成了3d頁面物體點擊事件,然后就是鼠標的移入到物體變色,移出時顏色還原,這和2d頁面的移入移出不太一樣,因為我們是給window對象加的監聽器,然后通過RayCaster對象來拾取到物體的,所以我們這里需要給window對象加鼠標移動事件來判斷鼠標是否移動我們的物體上。其步驟同上點擊事件一樣。

    window.addEventListener('mousemove', mouseMoveFuc);
    function mouseMoveFuc(){
        let raycaster = new THREE.Raycaster();//創建光線投射對象
        let mouse = new THREE.Vector2();//創建二維平面
        let intersectsObjArr = getSelsectOBj(mouse,raycaster, e);//通過封裝的getSelsectOBj函數獲取鼠標選中對象集合,e是點擊事件對象
        if(intersectsObjArr.length > 0){
            if(intersectsObjArr[0].object.name == 'redBall'){
                intersectsObjArr[0].object.material = new THREE.MeshPhongMaterial( { color: 'orange'});//移到物體上時顏色變成橘色
                document.getElementsByTagName('body')[0].style.cursor = 'pointer';//移到物體上時鼠標顯示為手

            }
        }else{
                myBall.material =  new THREE.MeshPhongMaterial( { color: 0xff0000});//移出物體時顏色變成原來的紅色
                document.getElementsByTagName('body')[0].style.cursor = 'default';//移出物體時鼠標顯示為默認
        }
    }

貼上最終代碼:運行一下,看下效果

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset=utf-8>
        <title>event</title>
        <style>
            body {
                margin: 0;
                padding: 0;
                height: 100vh;
                width: 100vw;
                overflow: hidden;
                background: url('img/bgImg.jpg') no-repeat fixed;
                background-size: 100% 100%;
            }
        </style>
    </head>
    <body>
    <script src="lib/three.min.js"></script>
    <script src="lib/OrbitControls.js"></script>
    <script>
        window.onload = function(){
            let scene,camera,renderer,myBall;
            initThreeScene();
            //物體的事件交互
            window.addEventListener('mousedown', mouseDownFuc);
            window.addEventListener('mousemove', mouseMoveFuc);
            function mouseDownFuc (e) {
                let raycaster = new THREE.Raycaster();//光線投射,用於確定鼠標點擊位置
	    let mouse = new THREE.Vector2();//創建二維平面
	    let intersects = getSelsectOBj(mouse,raycaster, e);
                if(intersects.length > 0) {
                    console.log(intersects[0])
                    if(intersects[0].object.name == 'myBall') {
                        myBall.position.y = 50;
                   }
                }
            }
            function mouseMoveFuc (e) {
                let raycaster = new THREE.Raycaster();//光線投射,用於確定鼠標點擊位置
	    let mouse = new THREE.Vector2();//創建二維平面
	    let intersects = getSelsectOBj(mouse,raycaster, e);
                if(intersects.length > 0) {
                   if(intersects[0].object.name == 'myBall') {
                       myBall.material =  new THREE.MeshPhongMaterial( { color: 'orange'});
                       document.getElementsByTagName('body')[0].style.cursor = 'pointer';
                   }
                }else {
                   myBall.material =  new THREE.MeshPhongMaterial( { color: 0xff0000});
                   document.getElementsByTagName('body')[0].style.cursor = 'default';
                }
            }
            //獲取事件操作對象
            function getSelsectOBj(mouse,raycaster, e) {
                //將html坐標系轉化為webgl坐標系,並確定鼠標點擊位置
                mouse.x =  e.clientX / renderer.domElement.clientWidth*2-1;
                mouse.y =  -(e.clientY / renderer.domElement.clientHeight*2)+1;
                //以camera為z坐標,確定所點擊物體的3D空間位置
                raycaster.setFromCamera(mouse,camera);
                //確定所點擊位置上的物體數量
                let intersects = raycaster.intersectObjects(scene.children, true);
                return intersects;
            }
            function initThreeScene() {
                scene = new THREE.Scene();
                camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 2000 );
                camera.position.set( 0, 50,300 );   
                renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });//antialias: true;讓渲染的平面是光滑的,alpha: true;讓渲染的3d背景透明。
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild(renderer.domElement );
                // 給場景添加一個環境光
                let ambientLight = new THREE.AmbientLight( 0xf5f5f5);
                scene.add( ambientLight );
                //輔助線
                let grid = new THREE.GridHelper( 400, 30, 0xcccccc, 0xcccccc );
                scene.add( grid );
                //創建的球
                let ball = new THREE.SphereGeometry( 25, 100, 100 );//25:球半徑 第一個100:水平分割面的數量. 第二個100:垂直分割面的數量.
                let ballColor = new THREE.MeshPhongMaterial( { color: 0xff0000 } );
                myBall = new THREE.Mesh( ball , ballColor );
                myBall.name = 'myBall';
                scene.add( myBall );
                let controls =new THREE.OrbitControls(camera, renderer.domElement);
                controls.enableZoom =true;//允許縮放
                //設置相機移動距離
                controls.minDistance = 1;
                controls.maxDistance = 2000;
                controls.enableRotate =true;
                function render() { 
                    requestAnimationFrame( render );
                    renderer.render( scene, camera );
                } 
                render();
                window.onresize = function () {
                    camera.aspect = window.innerWidth / window.innerHeight;//相機重置可視范圍
                    camera.updateProjectionMatrix();
                    renderer.setSize( window.innerWidth, window.innerHeight );//渲染器重新渲染可視范圍
                }
            }
        }
    </script>
    </body>
    </html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM