Threejs之光线投射Raycaster交互
这里写目录标题
- 前言
- 一、前置准备
- 1.1 代码
- 1.2 效果
- 二、添加交互事件
- 2.1 代码
- 2.2 效果
- 三、完整代码
前言
基于上篇文章Threejs之光线投射Raycaster我们知道了光线投射的基础用法,在本届我们将使用光线投射进行鼠标交互事件
一、前置准备
1.1 代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>html,body {margin: 0;padding: 0;width: 100%;height: 100%;}</style>
</head><body><script type="module">// 倒入轨道控制器import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'import * as THREE from "three";// 创建场景const scene = new THREE.Scene();// 创建相机const camera = new THREE.PerspectiveCamera( // 透视相机45, // 视角 角度数window.innerWidth / window.innerHeight, // 宽高比 占据屏幕0.1, // 近平面(相机最近能看到物体)1000, // 远平面(相机最远能看到物体));camera.position.set(0, 2, 20);// camera.lookAt(0, 0, 0);// 创建渲染器const renderer = new THREE.WebGLRenderer({antialias: true, // 抗锯齿});// 设置渲染器宽高renderer.setSize(window.innerWidth, window.innerHeight)// renderer(渲染器)的dom元素添加到我们的HTML文档中document.body.appendChild(renderer.domElement)// 开启坐标轴辅助器const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);const geometry = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));const geometry1 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));const geometry2 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));geometry1.position.x = 3;geometry2.position.x = -3;scene.add(geometry, geometry1, geometry2);// 控制器const control = new OrbitControls(camera, renderer.domElement);// 开启阻尼惯性,默认值为0.05control.enableDamping = true;// 渲染循环动画function animate() {// 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)requestAnimationFrame(animate);// 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用control.update();renderer.render(scene, camera);};// 执行动画animate();</script>
</body>
</html>
1.2 效果
可以看到我们在场景中放了三个球,并且设置了坐标轴辅助线。
二、添加交互事件
2.1 代码
添加鼠标交互事件,在鼠标点下去的时候我们去发射一束射线,让与之交互的物体做出一些改变,例如改变物体颜色,添加如下代码:
// 表示2D vector(二维向量)的类const mouse = new THREE.Vector2();let geometryArr = [geometry, geometry1, geometry2];const raycaster = new THREE.Raycaster();// 监听鼠标点击事件window.addEventListener("mousedown", (event) => {// 转换为一个位于二维空间中的点,在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;console.log(mouse.x, mouse.y);// 使用一个新的原点和方向来更新射线raycaster.setFromCamera(mouse, camera);// 每次点击循环设置物体初始颜色,如不设置会导致点击物体后颜色变后不能再变for(const geometry of geometryArr) {geometry.material.color.set(0xff0000);}// 相交的物体变色const itgeometrys = raycaster.intersectObjects(geometryArr);for(const itgeometry of itgeometrys) {itgeometry.object.material.color.set(0xcc33f4);}})
2.2 效果
可以看到我们已经完成了简单的物体交互。不要小瞧了光线投射,在我们与物体交互中起来很大的作用。
三、完整代码
最后给出本届完整代码,如下:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>html,body {margin: 0;padding: 0;width: 100%;height: 100%;}</style>
</head><body><script type="module">// 倒入轨道控制器import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'import * as THREE from "three";// 创建场景const scene = new THREE.Scene();// 创建相机const camera = new THREE.PerspectiveCamera( // 透视相机45, // 视角 角度数window.innerWidth / window.innerHeight, // 宽高比 占据屏幕0.1, // 近平面(相机最近能看到物体)1000, // 远平面(相机最远能看到物体));camera.position.set(0, 2, 20);// camera.lookAt(0, 0, 0);// 创建渲染器const renderer = new THREE.WebGLRenderer({antialias: true, // 抗锯齿});// 设置渲染器宽高renderer.setSize(window.innerWidth, window.innerHeight)// renderer(渲染器)的dom元素添加到我们的HTML文档中document.body.appendChild(renderer.domElement)// 开启坐标轴辅助器const axesHelper = new THREE.AxesHelper(5);scene.add(axesHelper);const geometry = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));const geometry1 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));const geometry2 = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 16), new THREE.MeshBasicMaterial({color: 0xff0000}));geometry1.position.x = 3;geometry2.position.x = -3;scene.add(geometry, geometry1, geometry2);// 控制器const control = new OrbitControls(camera, renderer.domElement);// 开启阻尼惯性,默认值为0.05control.enableDamping = true;// 表示2D vector(二维向量)的类const mouse = new THREE.Vector2();let geometryArr = [geometry, geometry1, geometry2];const raycaster = new THREE.Raycaster();// 监听鼠标点击事件window.addEventListener("mousedown", (event) => {// 转换为一个位于二维空间中的点,在标准化设备坐标中鼠标的二维坐标 —— X分量与Y分量应当在-1到1之间mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;console.log(mouse.x, mouse.y);// 使用一个新的原点和方向来更新射线raycaster.setFromCamera(mouse, camera);// 每次点击循环设置物体初始颜色,如不设置会导致点击物体后颜色变后不能再变for(const geometry of geometryArr) {geometry.material.color.set(0xff0000);}// 相交的物体变色const itgeometrys = raycaster.intersectObjects(geometryArr);for(const itgeometry of itgeometrys) {itgeometry.object.material.color.set(0xcc33f4);}})// 渲染循环动画function animate() {// 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)requestAnimationFrame(animate);// 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用control.update();renderer.render(scene, camera);};// 执行动画animate();</script>
</body>
</html>
在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。