在三维空间内判断鼠标点击的是哪个模型,核心的原理还是
射线碰撞
,*即从相机(camera)的中心点到屏幕上鼠标点组成一条射线,计算三维场景内哪些模型被射线穿过。*原理比较简单,计算比较复杂。主要是涉及了三个坐标系的转换:
-
将鼠标点从屏幕坐标系(y正向向下,x轴向右)转换到三维空间里的可视窗口的二维坐标系(正常的二维坐标系,但xy的区间是-1~1);
-
将三维空间里的可视窗口的二维坐标系点转换为三维空间的xyz坐标系
-
将2转换后的点和camera的中心点组成射线
基于vue的环境准备,可以参考我之前的
博文
<template>
<div id="app" @click="clickBox">
</template>
<script>
import {
Scene,
PerspectiveCamera,
WebGLRenderer,
Mesh,
BoxGeometry, MeshBasicMaterial, Raycaster, Vector2
} from 'three';
import {OrbitControls} from "@/lib/OrbitControls"
export default {
name: 'App',
components: {},
mounted() {
let scene = new Scene();
let camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
let renderer = new WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
let app = document.getElementById("app")
app.appendChild(renderer.domElement);
//加载场景控制插件
let controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.enableZoom = true;
controls.autoRotate = false;
controls.autoRotateSpeed = 3;
controls.enablePan = true;
controls.enableKeys = true;
controls.keyPanSpeed = 7;
controls.keys = {
LEFT: 37,
UP: 38,
RIGHT: 39,
BOTTOM: 40
this.controls = controls;
this.createBox(scene);
this.createBox(scene);
this.createBox(scene);
camera.position.z = 5;
this.camera = camera;
this.scene = scene;
//渲染场景
let animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
animate();
methods: {
//生成随机盒子模型
createBox(scene) {
let geometry = new BoxGeometry();
let material = new MeshBasicMaterial({color: 0x00ff00});
let cube = new Mesh(geometry, material);
cube.position.x = Math.random() * 6-3
cube.position.y = Math.random() * 6-3
scene.add(cube);
clickBox(event) {
console.log(Math.random().toString(16))
let raycaster = new Raycaster();
let mouse = new Vector2();
console.log(this.scene.children)
//将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1
mouse.y = 1-(event.clientY / window.innerHeight) * 2
console.log(mouse)
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera(mouse, this.camera);
// 获取raycaster直线和所有模型相交的数组集合
var intersects = raycaster.intersectObjects(this.scene.children);
console.log(intersects);
//将所有的相交的模型的颜色设置为红色
for (var i = 0; i < intersects.length; i++) {
intersects[i].object.material.color.set(0xff0000);
</script>
<style>
#app {
body, html {
margin: 0;
padding: 0;
</style>
网上很多的代码写的都是
mouse.y = (event.clientY / window.innerHeight) * 2 + 1;
可以看出来这个y一直都是大于1的
object.traverse(child=>{
// if(object.name==='model.glb') {
// console.log("加工中心",child.name)
// // flashingName = "mesh_8"
if(child instanceof THREE.Mesh
var objects=[];
var raycaster= new THREE.Raycaster();
var mouse = new THREE.Vector2(),
INTERSECTED, SELECTED;
需要把你要实现的效果的geo
这个小案例是当初我在学习的时候,小的一个小案例,代码还需要进一步优化;还请谅解~~;主要用到了threeJS创建mesh,创建平面,设置mesh的平移,旋转、缩放、自传、透明度、拉伸等这些小功能;
(点击每个mesh,mesh的颜色会变为红色)
1 需要加载这些相关的js文件
2 下面是实现的一些小功能
3 下面是相关代码,代码还没有优化,请谅解~~(具...