赞
踩
目录
1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子
2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove
说明:该案例是基于Vue2创建,如果未使用Ve2请自行修改代码,另外由于使用的是已经下载的Three.js,所以运行前请确保已安装Three.js以方便引入,未安装可以使用 npm install three 进行安装
先创建两个基本模型为 光线投射Raycaster 做铺垫
下面是一个名为 model 组件的编写,读者可以自行挂载在Vue示例上
另外如果有 model 命名带来的错误,可以在文件 vue.config.js 中添加配置 lintOnSave: false
- <template>
- <div ref="container">
-
- </div>
- </template>
-
- <script>
- import * as THREE from "three";
- import {OrbitControls} from "three/addons/controls/OrbitControls.js";
-
- export default {
- name: "model",
- data() {
- return {
- //场景
- scene: null,
- //摄影机
- camera: null,
- //渲染器
- renderer: null,
- //相机控件
- controls: null,
- }
- },
- mounted() {
- // 调用方法创建场景、相机、渲染器和相机控件
- this.createScene();
- this.createCamera();
- this.createRenderer();
- this.createControls();
-
- // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
- const cube1 = new THREE.Mesh(
- new THREE.BoxGeometry(3, 2, 1),
- new THREE.MeshBasicMaterial({color: 0xff0000})
- );
- const cube2 = new THREE.Mesh(
- new THREE.BoxGeometry(1, 2, 3),
- new THREE.MeshBasicMaterial({color: 0x00ff00})
- );
- cube1.position.set(-2, 0, 0);
- cube2.position.set(2, 0, 0);
- this.scene.add(cube1, cube2);
-
- const render = () => {
- //手动更改相机的变换后,必须调用controls.update()
- this.controls.update()
- this.renderer.render(this.scene, this.camera);
- requestAnimationFrame(render);
- };
- render();
- },
- methods: {
- //创建场景
- createScene() {
- this.scene = new THREE.Scene();
- },
- //创建相机
- createCamera() {
- this.camera = new THREE.PerspectiveCamera(
- 45,
- window.innerWidth / window.innerHeight,
- 1,
- 1000
- );
- this.camera.position.set(0, 0, 5);
- },
- //创建渲染器
- createRenderer() {
- this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
- this.renderer.setSize(window.innerWidth, window.innerHeight);
- this.$refs.container.appendChild(this.renderer.domElement);
- },
- //创建相机控件
- createControls() {
- this.controls = new OrbitControls(this.camera, this.renderer.domElement);
- }
- }
- };
- </script>
-
- <style scoped>
-
- </style>

重点!!!
- template>
- <div ref="container">
- <div id="infoBox"></div>
- </div>
- </template>
-
- //盒子样式如下: (要是觉得盒子丑大家可以自己修改,哈哈)
- #infoBox{
- display: none;
- position: absolute;
- top: 0;
- left: 0;
- background-color: #fff;
- border:1px solid #ccc;
- padding: 5px;
- }

为了大家方便对照官方文档学习,所以我直接引用了官文文档的源码,大家可以对照官文修改代码进行实验加深理解
官网地址:https://threejs.org/docs/index.html#api/zh/core/Raycaster
- const raycaster = new THREE.Raycaster();
- //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
- const pointer = new THREE.Vector2();
window.addEventListener('pointermove', onPointerMove);
- const infoBox = document.querySelector('#infoBox') //获取Dom元素
- const onPointerMove = (event) => { //如果不使用箭头函数需要注意this指向问题
- // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
- pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
- pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
- //计算物体和射线的焦点
- // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
- // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
- // 相交部分和.intersectObject所返回的格式是相同的。
- const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
- //没有相交物体时
- if (intersects.length === 0) {
- console.log('隐藏');
- infoBox.style.display = "none";
- return;
- }
- //有相交物体时
- if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
- console.log('显示');
- //设置信息
- infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
- <br>宽:${intersects[0].object.geometry.parameters.width}<br>
- 高:${intersects[0].object.geometry.parameters.height}`;
- infoBox.style.display = "block";
- console.log(event.clientX);
- infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
- infoBox.style.top = event.clientY + "px"
- }
- }

raycaster.setFromCamera(pointer, this.camera);
以上就是 光线投射Raycaster 的使用步骤
- <template>
- <div ref="container">
- <div id="infoBox"></div>
- </div>
- </template>
-
- <script>
- import * as THREE from "three";
- import {OrbitControls} from "three/addons/controls/OrbitControls.js";
-
- export default {
- name: "model",
- data() {
- return {
- //场景
- scene: null,
- //摄影机
- camera: null,
- //渲染器
- renderer: null,
- //相机控件
- controls: null,
- }
- },
- mounted() {
- // 调用方法创建场景、相机、渲染器和相机控件
- this.createScene();
- this.createCamera();
- this.createRenderer();
- this.createControls();
-
- // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
- const cube1 = new THREE.Mesh(
- new THREE.BoxGeometry(3, 2, 1),
- new THREE.MeshBasicMaterial({color: 0xff0000})
- );
- const cube2 = new THREE.Mesh(
- new THREE.BoxGeometry(1, 2, 3),
- new THREE.MeshBasicMaterial({color: 0x00ff00})
- );
- cube1.position.set(-2, 0, 0);
- cube2.position.set(2, 0, 0);
- this.scene.add(cube1, cube2);
-
- //1.创建 Raycaster 实例
- const raycaster = new THREE.Raycaster();
- const pointer = new THREE.Vector2(); //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
- //3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove
- const infoBox = document.querySelector('#infoBox') //获取Dom元素
- const onPointerMove = (event) => { //如果不使用箭头函数需要注意this指向问题
- // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
- pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
- pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
- //计算物体和射线的焦点
- // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
- // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
- // 相交部分和.intersectObject所返回的格式是相同的。
- const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
- //没有相交物体时
- if (intersects.length === 0) {
- console.log('隐藏');
- infoBox.style.display = "none";
- return;
- }
- //有相交物体时
- if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
- console.log('显示');
- //设置信息
- infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
- <br>宽:${intersects[0].object.geometry.parameters.width}<br>
- 高:${intersects[0].object.geometry.parameters.height}`;
- infoBox.style.display = "block";
- console.log(event.clientX);
- infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
- infoBox.style.top = event.clientY + "px"
- }
- }
- //2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
- window.addEventListener('pointermove', onPointerMove);
-
- const render = () => {
- // 4.通过摄像机和鼠标位置更新射线
- raycaster.setFromCamera(pointer, this.camera);
- //手动更改相机的变换后,必须调用controls.update()
- this.controls.update()
- this.renderer.render(this.scene, this.camera);
- requestAnimationFrame(render);
- };
- render();
- },
- methods: {
- //创建场景
- createScene() {
- this.scene = new THREE.Scene();
- },
- //创建相机
- createCamera() {
- this.camera = new THREE.PerspectiveCamera(
- 45,
- window.innerWidth / window.innerHeight,
- 1,
- 1000
- );
- this.camera.position.set(0, 0, 5);
- },
- //创建渲染器
- createRenderer() {
- this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
- this.renderer.setSize(window.innerWidth, window.innerHeight);
- this.$refs.container.appendChild(this.renderer.domElement);
- },
- //创建相机控件
- createControls() {
- this.controls = new OrbitControls(this.camera, this.renderer.domElement);
- }
- }
- };
- </script>
-
- <style scoped>
- #infoBox {
- display: none;
- position: absolute;
- top: 0;
- left: 0;
- background-color: #fff;
- border: 1px solid #ccc;
- padding: 5px;
- }
- </style>

要是读者觉得帮到你们了,麻烦点个赞鼓励一下,以便鼓舞我这个新手小白,谢谢大家
另外大家要有什么疑问或者是指教都可以在评论区发出来,作者看到一定回复,谢谢大家
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。