three.js Raycaster 使用小结

137 阅读1分钟

Raycaster 是什么有什么用作

  • Raycaster 光线投影是用来做三维事件判断的API
  • Raycaster 主要通过 与 Vector2 与本身的属性 intersectObjects 来判断是否点击了某个3D环境中有物体

使用示例


<template>
    <div id="parkingLot" ref="parkingLot"></div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

const parkingLot = ref();

onMounted(() => {
    const DOMEl = parkingLot.value;
    const width = DOMEl.clientWidth;
    const height = DOMEl.clientHeight;

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(width, height);
    DOMEl.appendChild(renderer.domElement);

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(45, width / height, 1, 2000);
    camera.position.set(0, 5, 50);
    camera.lookAt(0, 0, 0);

    const controls = new OrbitControls(camera, renderer.domElement);

    const cubes = [];
    const geometry = new THREE.BoxGeometry();
    for (let i = 0; i < 5; i++) {
        const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
        const cube = new THREE.Mesh(geometry, material);
        cube.position.x = Math.random() * 4 - 2;
        cube.position.y = Math.random() * 4 - 2;
        cube.position.z = Math.random() * 4 - 2;
        cubes.push(cube);
        scene.add(cube);
    }

    const raycaster = new THREE.Raycaster();
    const mouse = new THREE.Vector2();

    const onMouseClick = (event) => {
        const rect = DOMEl.getBoundingClientRect();
        mouse.x = ((event.clientX - rect.left) / width) * 2 - 1;
        mouse.y = -((event.clientY - rect.top) / height) * 2 + 1;

        raycaster.setFromCamera(mouse, camera);
        const intersects = raycaster.intersectObjects(scene.children);

        if (intersects.length > 0) {
            const intersectedObject = intersects[0].object;
            console.log('Hit object:', intersectedObject);
            intersectedObject.material.color.set(0xff0000);
        } else {
            console.log('No objects hit.');
        }
    };

    window.addEventListener('click', onMouseClick);

    function animate() {
        requestAnimationFrame(animate);
        cubes.forEach(cube => {
            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;
        });
        renderer.render(scene, camera);
    }

    animate();

    onUnmounted(() => {
        window.removeEventListener('click', onMouseClick);
        controls.dispose();
        renderer.dispose();
    });
});
</script>

<style lang="scss" scoped>
#parkingLot {
    width: 940px;
    height: 940px;
    border: 1px solid #ccc;
    margin: 30px auto;
}
</style>