Three.js 实现点击模型改变颜色
想实现点击模型,改变模型颜色的效果。在网上看了一些代码,发现特别搞笑,很多的博客给出的计算代码都是错误的,根本无法实现点击效果,还在不同的博客相互的复制,只能感叹抄袭党太多。下面我简单的介绍一些我的方法,我是在Vue中开发的。
三维空间点击事件的原理
在三维空间内判断鼠标点击的是哪个模型,核心的原理还是射线碰撞
,*即从相机(camera)的中心点到屏幕上鼠标点组成一条射线,计算三维场景内哪些模型被射线穿过。*原理比较简单,计算比较复杂。主要是涉及了三个坐标系的转换:
- 将鼠标点从屏幕坐标系(y正向向下,x轴向右)转换到三维空间里的可视窗口的二维坐标系(正常的二维坐标系,但xy的区间是-1~1);
- 将三维空间里的可视窗口的二维坐标系点转换为三维空间的xyz坐标系
- 将2转换后的点和camera的中心点组成射线
环境准备
基于vue的环境准备,可以参考我之前的博文
代码实现
<template>
<div id="app" @click="clickBox">
</div>
</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的