簡體   English   中英

THREE.JS:帶有光線投射器和透視相機的點擊事件

[英]THREE.JS : click event with raycaster and perspective camera

我想為 three.js 中的 web 頁面創建一個菜單,其中每個選項卡都由 object (二維矩形)具體化,我們通過單擊右側的矩形訪問網站頁面。 為此,我讀到我必須使用當我右鍵單擊鼠標時觸發的光線投射器,然后使用相交對象的數組來查看我單擊了哪些對象。

我在互聯網上嘗試了很多教程,但從未成功擁有用於右鍵單擊的功能性 raycaster 和 eventListener。 raycast function 只是從 three.js 文檔中復制/粘貼。

這是我的代碼(稱為 script.js),你看到我做錯了什么或者你有什么建議可以改進嗎? 提前感謝您的幫助!

var camera, scene, rendu;
var geometrie, materiau, mesh;
var controle;
var couleur, plan, onglet1, onglet2, onglet3, onglet4, onglet5, onglet6;
var r, t;
var rayon, souris;

init();

function init() {
    r = 3;
    t = 1.1;
    // ---------- scene et camera --------- //
    camera = new THREE.PerspectiveCamera( 70 , window.innerWidth / window.innerHeight , 0.01 , 10 );
    camera.position.set( 0 , 0 , 4 );
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000000);

    // --------- cube --------- //
    //materiau = new THREE.MeshBasicMaterial( { color: 0xffffff});
    //geometrie = new THREE.BoxGeometry( t , 3*t , t );
    //mesh = new THREE.Mesh( geometrie, materiau );
    //scene.add( mesh );

    // --------- onglets ---------- //
    couleur = new THREE.MeshBasicMaterial( {color: 0x031f3c , side: THREE.DoubleSide } );
    plan = new THREE.PlaneGeometry( 0.75 , 0.4 );

    onglet1 = new THREE.Mesh( plan , couleur );
    onglet1.position.set( 0, 0, r );
    scene.add( onglet1 );

    onglet2 = new THREE.Mesh( plan , couleur );
    onglet2.position.set( r*Math.sqrt(3/4), 0, 0.5*r );
    onglet2.rotation.y = Math.PI / 3;
    scene.add( onglet2 );

    onglet3 = new THREE.Mesh( plan , couleur );
    onglet3.position.set( r*Math.sqrt(3/4), 0, -0.5*r );
    onglet3.rotation.y = 2 *Math.PI / 3;
    scene.add( onglet3 );

    onglet4 = new THREE.Mesh( plan , couleur );
    onglet4.position.set( 0, 0, -r );
    scene.add( onglet4 );

    onglet5 = new THREE.Mesh( plan , couleur );
    onglet5.position.set( -r*Math.sqrt(3/4), 0, -0.5*r );
    onglet5.rotation.y = -2*Math.PI / 3;
    scene.add( onglet5 );

    onglet6 = new THREE.Mesh( plan , couleur );
    onglet6.position.set( -r*Math.sqrt(3/4), 0, 0.5*r );
    onglet6.rotation.y = -Math.PI / 3;
    scene.add( onglet6 );

    // ---------- rendu ------------- //
    rendu = new THREE.WebGLRenderer( { antialias: true} );
    rendu.setSize( window.innerWidth, window.innerHeight );
    rendu.setPixelRatio(window.devicePixelRatio);
    rendu.setAnimationLoop( animation );
    document.body.appendChild( rendu.domElement );

    // ------------- liens sur onglets ------------- //
    //window.addEventListener('click', onclick, false);
    // ecouter l'event de clic sur la souris
    // on ajoute un capteur de rayon qui regarde si on croise un objet de la scene
    // si c'est le cas on fait ce qu'on veut en fonction de l'objet

    rayon = new THREE.Raycaster();
    rendu.domElement.addEventListener( 'click', raycast, false );

}

function animation() {
    rendu.render( scene, camera );
    controle.update();
}

function raycast ( e ) {
    //1. sets the mouse position with a coordinate system where the center
    // of the screen is the origin
    souris.x = ( e.clientX / window.innerWidth ) * 2 - 1;
    souris.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
    //2. set the picking ray from the camera position and mouse coordinates
    rayon.setFromCamera( souris, camera );
    //3. compute intersections
    var intersections = rayon.intersectObjects( scene.children );
    intersections[0]
}

// ---------- orbitControls --------- //
controle = new THREE.OrbitControls(camera, rendu.domElement);
controle.minPolarAngle = Math.PI / 2;
controle.maxPolarAngle = Math.PI / 2;
controle.autoRotate = true;
controle.autoRotateSpeed = -0.1;
controle.enableZoom = false;
controle.mouseButtons = {
    LEFT: THREE.MOUSE.ROTATE,
    MIDDLE: THREE.MOUSE.DOLLY,
    RIGHT: THREE.MOUSE.ROTATE
}

// ----------- redimensionnement fenetre ------------ //
window.addEventListener('resize', function() {
    camera.aspect = window.innerWidth / window.innerHeight ;
    camera.updateProjectionMatrix();
    rendu.setSize(window.innerWidth, window.innerHeight);
}, false);

let loader = new THREE.GLTFLoader();
loader.load('voiture/scene.gltf', function(gltf){ 
    voiture = gltf.scene.children[0];
    //voiture.scale.set(0.5, 0.5, 0.5);
    scene.add(gltf.scene);
    rendu.render(scene, camera);
});

這是我的 html 代碼(稱為 index.html)

<!DOCTYPE html>
<html lang="fr">
<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>test</title>

    <style>
        body{margin: 0px;}
        canvas{width: 100%; height: 100%;}
    </style>
</head>


<body>
    <script src="js/build/three.js"></script>
    <script src="js/build/three.min.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/GLTFLoader.js"></script>
    <script src="js/script.js"></script>
</body>
</html>

我相信您的問題源於未將souris變量初始化為THREE.Vector2() 您的代碼歸結為:

var souris;
souris.x = xxx;
souris.y = yyy;

var rayon = new THREE.Raycaster();
rayon.setFromCamera( souris, camera );

Raycaster.setFromCamera 要求您使用 Vector2作為其第一個參數,但您從未創建過Vector2

要解決此問題,只需確保在分配其值之前聲明souris = THREE.Vector2()

var souris = THREE.Vector2();
souris.x = xxx;
souris.y = yyy;

var rayon = new THREE.Raycaster();
rayon.setFromCamera( souris, camera );

在將souris初始化為Vector2 ,您將投射光線,然后在嘗試更改任何內容之前檢查它是否實際上與 object 相交。

在第一個相交的 object 上設置新材質,以避免更改場景中所有對象的顏色,因為它們共享相同的材質。

function raycast ( e ) {
    //1. sets the mouse position with a coordinate system where the center
    // of the screen is the origin
    souris = new THREE.Vector2();
    souris.x = ( e.clientX / window.innerWidth ) * 2 - 1;
    souris.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
    //2. set the picking ray from the camera position and mouse coordinates
    rayon.setFromCamera( souris, camera );
    //3. compute intersections
    var intersections = rayon.intersectObjects( scene.children );

    if (intersections.length) {
        intersections[0].object.material = 
            new THREE.MeshBasicMaterial({ 
                color: 0xff0000, 
                side: THREE.DoubleSide 
            });

        if (intersections[0].object.url) { window.open(intersections[0].object.url, '_blank'); }
    }
}

我希望這可以解決您的問題...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM