当前位置:   article > 正文

Three.js中光线投射Raycaster的简单使用案例 与模型的交互,当鼠标移动到模型时出现信息框_threejs点击模型出现对话框

threejs点击模型出现对话框

目录

说明 

 创建两个模型

基础代码 

基础代码效果图如下:

重点!!! 

 创建光线投射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

基础代码 

  1. <template>
  2. <div ref="container">
  3. </div>
  4. </template>
  5. <script>
  6. import * as THREE from "three";
  7. import {OrbitControls} from "three/addons/controls/OrbitControls.js";
  8. export default {
  9. name: "model",
  10. data() {
  11. return {
  12. //场景
  13. scene: null,
  14. //摄影机
  15. camera: null,
  16. //渲染器
  17. renderer: null,
  18. //相机控件
  19. controls: null,
  20. }
  21. },
  22. mounted() {
  23. // 调用方法创建场景、相机、渲染器和相机控件
  24. this.createScene();
  25. this.createCamera();
  26. this.createRenderer();
  27. this.createControls();
  28. // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
  29. const cube1 = new THREE.Mesh(
  30. new THREE.BoxGeometry(3, 2, 1),
  31. new THREE.MeshBasicMaterial({color: 0xff0000})
  32. );
  33. const cube2 = new THREE.Mesh(
  34. new THREE.BoxGeometry(1, 2, 3),
  35. new THREE.MeshBasicMaterial({color: 0x00ff00})
  36. );
  37. cube1.position.set(-2, 0, 0);
  38. cube2.position.set(2, 0, 0);
  39. this.scene.add(cube1, cube2);
  40. const render = () => {
  41. //手动更改相机的变换后,必须调用controls.update()
  42. this.controls.update()
  43. this.renderer.render(this.scene, this.camera);
  44. requestAnimationFrame(render);
  45. };
  46. render();
  47. },
  48. methods: {
  49. //创建场景
  50. createScene() {
  51. this.scene = new THREE.Scene();
  52. },
  53. //创建相机
  54. createCamera() {
  55. this.camera = new THREE.PerspectiveCamera(
  56. 45,
  57. window.innerWidth / window.innerHeight,
  58. 1,
  59. 1000
  60. );
  61. this.camera.position.set(0, 0, 5);
  62. },
  63. //创建渲染器
  64. createRenderer() {
  65. this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
  66. this.renderer.setSize(window.innerWidth, window.innerHeight);
  67. this.$refs.container.appendChild(this.renderer.domElement);
  68. },
  69. //创建相机控件
  70. createControls() {
  71. this.controls = new OrbitControls(this.camera, this.renderer.domElement);
  72. }
  73. }
  74. };
  75. </script>
  76. <style scoped>
  77. </style>

基础代码效果图如下:


重点!!! 

 创建光线投射Raycaster实例步骤

1.准备一个盒子,用来展示模型的长宽高信息,初始化时先隐藏该盒子

  1. template>
  2. <div ref="container">
  3. <div id="infoBox"></div>
  4. </div>
  5. </template>
  6. //盒子样式如下: (要是觉得盒子丑大家可以自己修改,哈哈)
  7. #infoBox{
  8. display: none;
  9. position: absolute;
  10. top: 0;
  11. left: 0;
  12. background-color: #fff;
  13. border:1px solid #ccc;
  14. padding: 5px;
  15. }

2.创建光线投射Raycaster实例

为了大家方便对照官方文档学习,所以我直接引用了官文文档的源码,大家可以对照官文修改代码进行实验加深理解 

官网地址:https://threejs.org/docs/index.html#api/zh/core/Raycaster

        1.创建 Raycaster 实例 

  1. const raycaster = new THREE.Raycaster();
  2. //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
  3. const pointer = new THREE.Vector2();

         2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改

window.addEventListener('pointermove', onPointerMove);

        3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove 

  1. const infoBox = document.querySelector('#infoBox') //获取Dom元素
  2. const onPointerMove = (event) => { //如果不使用箭头函数需要注意this指向问题
  3. // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  4. pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
  5. pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
  6. //计算物体和射线的焦点
  7. // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
  8. // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
  9. // 相交部分和.intersectObject所返回的格式是相同的。
  10. const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
  11. //没有相交物体时
  12. if (intersects.length === 0) {
  13. console.log('隐藏');
  14. infoBox.style.display = "none";
  15. return;
  16. }
  17. //有相交物体时
  18. if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
  19. console.log('显示');
  20. //设置信息
  21. infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
  22. <br>宽:${intersects[0].object.geometry.parameters.width}<br>
  23. 高:${intersects[0].object.geometry.parameters.height}`;
  24. infoBox.style.display = "block";
  25. console.log(event.clientX);
  26. infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
  27. infoBox.style.top = event.clientY + "px"
  28. }
  29. }

        4.通过摄像机和鼠标位置更新射线

raycaster.setFromCamera(pointer, this.camera);

以上就是 光线投射Raycaster 的使用步骤


完整代码如下:

  1. <template>
  2. <div ref="container">
  3. <div id="infoBox"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import * as THREE from "three";
  8. import {OrbitControls} from "three/addons/controls/OrbitControls.js";
  9. export default {
  10. name: "model",
  11. data() {
  12. return {
  13. //场景
  14. scene: null,
  15. //摄影机
  16. camera: null,
  17. //渲染器
  18. renderer: null,
  19. //相机控件
  20. controls: null,
  21. }
  22. },
  23. mounted() {
  24. // 调用方法创建场景、相机、渲染器和相机控件
  25. this.createScene();
  26. this.createCamera();
  27. this.createRenderer();
  28. this.createControls();
  29. // 创建两个不同大小的立方体模型,材质使用不受光照影响的 MeshBasicMaterial 材质
  30. const cube1 = new THREE.Mesh(
  31. new THREE.BoxGeometry(3, 2, 1),
  32. new THREE.MeshBasicMaterial({color: 0xff0000})
  33. );
  34. const cube2 = new THREE.Mesh(
  35. new THREE.BoxGeometry(1, 2, 3),
  36. new THREE.MeshBasicMaterial({color: 0x00ff00})
  37. );
  38. cube1.position.set(-2, 0, 0);
  39. cube2.position.set(2, 0, 0);
  40. this.scene.add(cube1, cube2);
  41. //1.创建 Raycaster 实例
  42. const raycaster = new THREE.Raycaster();
  43. const pointer = new THREE.Vector2(); //创建一个二维向量为后面 Raycaster 实例调用 .setFromCamera 方法做准备
  44. //3.定义窗口触发 pointermove 事件所执行的回调函数 onPointerMove
  45. const infoBox = document.querySelector('#infoBox') //获取Dom元素
  46. const onPointerMove = (event) => { //如果不使用箭头函数需要注意this指向问题
  47. // 修改 pointer 的值:将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  48. pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
  49. pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
  50. //计算物体和射线的焦点
  51. // 方法 .intersectObjects ( objects : Array, recursive : Boolean, optionalTarget : Array ) : Array
  52. // 作用:检测所有在射线与这些物体之间,包括或不包括后代的相交部分。返回结果时,相交部分将按距离进行排序,最近的位于第一个),
  53. // 相交部分和.intersectObject所返回的格式是相同的。
  54. const intersects = raycaster.intersectObjects(this.scene.children);//返回和射线相交的一组物体,值为数组
  55. //没有相交物体时
  56. if (intersects.length === 0) {
  57. console.log('隐藏');
  58. infoBox.style.display = "none";
  59. return;
  60. }
  61. //有相交物体时
  62. if (intersects.length > 0) { //其中数组第一个值的 object属性值就是鼠标放在屏幕上离我们最近的模型
  63. console.log('显示');
  64. //设置信息
  65. infoBox.innerHTML = `长:${intersects[0].object.geometry.parameters.depth}
  66. <br>宽:${intersects[0].object.geometry.parameters.width}<br>
  67. 高:${intersects[0].object.geometry.parameters.height}`;
  68. infoBox.style.display = "block";
  69. console.log(event.clientX);
  70. infoBox.style.left = event.clientX + "px"; //记得一定要拼接 px 我就是开始忘记了,导致信息框不移动
  71. infoBox.style.top = event.clientY + "px"
  72. }
  73. }
  74. //2.为窗口绑定事件 pointermove 想使用点击事件 click 的可以自行修改
  75. window.addEventListener('pointermove', onPointerMove);
  76. const render = () => {
  77. // 4.通过摄像机和鼠标位置更新射线
  78. raycaster.setFromCamera(pointer, this.camera);
  79. //手动更改相机的变换后,必须调用controls.update()
  80. this.controls.update()
  81. this.renderer.render(this.scene, this.camera);
  82. requestAnimationFrame(render);
  83. };
  84. render();
  85. },
  86. methods: {
  87. //创建场景
  88. createScene() {
  89. this.scene = new THREE.Scene();
  90. },
  91. //创建相机
  92. createCamera() {
  93. this.camera = new THREE.PerspectiveCamera(
  94. 45,
  95. window.innerWidth / window.innerHeight,
  96. 1,
  97. 1000
  98. );
  99. this.camera.position.set(0, 0, 5);
  100. },
  101. //创建渲染器
  102. createRenderer() {
  103. this.renderer = new THREE.WebGLRenderer({antialias: true}); //antialias:是否执行抗锯齿,默认为false.
  104. this.renderer.setSize(window.innerWidth, window.innerHeight);
  105. this.$refs.container.appendChild(this.renderer.domElement);
  106. },
  107. //创建相机控件
  108. createControls() {
  109. this.controls = new OrbitControls(this.camera, this.renderer.domElement);
  110. }
  111. }
  112. };
  113. </script>
  114. <style scoped>
  115. #infoBox {
  116. display: none;
  117. position: absolute;
  118. top: 0;
  119. left: 0;
  120. background-color: #fff;
  121. border: 1px solid #ccc;
  122. padding: 5px;
  123. }
  124. </style>

效果图如下 :


 结尾

要是读者觉得帮到你们了,麻烦点个赞鼓励一下,以便鼓舞我这个新手小白,谢谢大家

另外大家要有什么疑问或者是指教都可以在评论区发出来,作者看到一定回复,谢谢大家

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/928630
推荐阅读
  

闽ICP备14008679号