【问题标题】:Mouseover doesn't work properly compared to Click event in Threejs与 Threejs 中的 Click 事件相比,鼠标悬停无法正常工作
【发布时间】:2021-01-05 22:44:12
【问题描述】:

我对 Three.js 有点陌生

我正在尝试加载 GLTF 模型,添加 mouseover 和 mouseout 事件,其中第一个将更改 GLTF 颜色,而第二个将其恢复为原始颜色。

到目前为止,我已经能够实现它 - 部分地,正如它出现在 this video 中那样,它不会改变任何东西,除非鼠标指针来自(可能失焦?)直接进入 GLTF 模型而不去通过黑色背景。

我正在使用的code

const loader = new GLTFLoader();
loader.load('models/box.glb', function (gltf) {
    gltf.scene.traverse(function (child) {
        if (child.isMesh) {
            let m = child;
            m.receiveShadow = true;
            m.castShadow = true;
            m.material.flatShading = true;
            sceneMeshes.push(m);
        }
        if (child.isLight) {
            let l = child;
            l.castShadow = true;
            l.shadow.bias = -.003;
            l.shadow.mapSize.width = 2048;
            l.shadow.mapSize.height = 2048;
        }
    });
    scene.add(gltf.scene);
    console.log(gltf.scene);
}, (xhr) => {
    console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
    console.log(error);
});
const raycaster = new THREE.Raycaster();
const sceneMeshes = new Array();
renderer.domElement.addEventListener('mouseover', onMouseMove, false);
renderer.domElement.addEventListener('mouseout', onMouseOut, false);
function onMouseMove(event) {
    const mouse = {
        x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
        y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
    };
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(sceneMeshes, false);
    if (intersects.length > 0) {
        intersects[0].object.material.color.set(0xffff00);
    }
}
function onMouseOut(event) {
    const mouse = {
        x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
        y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
    };
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(sceneMeshes, false);
    if (intersects.length > 0) {
        intersects[0].object.material.color.set(0xff0000);
    }
}

知道我可能做错了什么吗?

【问题讨论】:

    标签: javascript three.js gltf


    【解决方案1】:

    我通过使用mousemove 事件和onMouseMove 事件中的以下代码解决了这个问题:

    if (intersects.length > 0) {
        INTERSECTED = intersects[0].object;
    
        if (intersects[0].object) {
            INTERSECTED.material.color.set(0xff0000);
            console.log("Touching")
        }
            
    } else {
        INTERSECTED.material.color.set(0xfff000);
        console.log("Not touching")
    }
    

    基本上我在错误的地方使用了 else 语句 - 就在 if (intersects[0].object) 之后

    【讨论】:

      【解决方案2】:

      用这个简化的代码试试吧:

      let camera, scene, renderer, mesh;
      let raycaster, mouse;
      
      let currentIntersection = null;
      
      init();
      animate();
      
      function init() {
      
        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
        camera.position.z = 4;
      
        raycaster = new THREE.Raycaster();
        mouse = new THREE.Vector2();
      
        scene = new THREE.Scene();
      
        const geometry = new THREE.BoxBufferGeometry();
        const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
      
        mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
      
        renderer = new THREE.WebGLRenderer({
          antialias: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
      
        renderer.domElement.addEventListener('pointermove', onMouseMove, false);
      
      }
      
      function animate() {
      
        requestAnimationFrame(animate);
      
        mesh.rotation.x += 0.01;
        mesh.rotation.y += 0.02;
      
        renderer.render(scene, camera);
      
      }
      
      function onMouseMove(event) {
        mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
        mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObject(scene, true);
        if (intersects.length > 0) {
          currentIntersection = intersects[0].object;
          currentIntersection.material.color.set(0xffff00);
        } else {
          if (currentIntersection !== null) {
            currentIntersection.material.color.set(0xff0000);
            currentIntersection = null;
          }
        }
      }
      body {
        margin: 0;
      }
      
      canvas {
        display: block;
      }
      <script src="https://cdn.jsdelivr.net/npm/three@0.120.1/build/three.js"></script>

      您通常只需要一个pointermove 事件侦听器即可实现“悬停”效果。

      【讨论】:

      • 感谢 @Mugen87,它适用于基本 Mesh,但不适用于 GLTFLoader。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2016-04-27
      • 1970-01-01
      • 2023-04-01
      相关资源
      最近更新 更多