目录
说明
创建两个模型
基础代码
基础代码效果图如下:
重点!!!
创建光线投射Raycaster实例步骤
1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子
2.创建光线投射Raycaster实例
1.创建 Raycaster 实例
2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove
4.通过摄像机和鼠标位置更新射线
完整代码如下:
效果图如下 :
结尾
说明
说明:该案例是基于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>
基础代码效果图如下:
重点!!!
创建光线投射Raycaster实例步骤
1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子
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;
}
2.创建光线投射Raycaster实例
为了大家方便对照官方文档学习,所以我直接引用了官文文档的源码,大家可以对照官文修改代码进行实验加深理解
官网地址:https://threejs.org/docs/index.html#api/zh/core/Raycaster
1.创建 Raycaster 实例
const raycaster = new THREE.Raycaster();
//创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
const pointer = new THREE.Vector2();
2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
window.addEventListener('pointermove', onPointerMove);
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"
}
}
4.通过摄像机和鼠标位置更新射线
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>
效果图如下 :
结尾
要是读者觉得帮到你们了,麻烦点个赞鼓励一下,以便鼓舞我这个新手小白,谢谢大家文章来源:https://www.toymoban.com/news/detail-753955.html
另外大家要有什么疑问或者是指教都可以在评论区发出来,作者看到一定回复,谢谢大家文章来源地址https://www.toymoban.com/news/detail-753955.html
到了这里,关于Three.js中光线投射Raycaster的简单使用案例 与模型的交互,当鼠标移动到模型时出现信息框的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!