当前位置:   article > 正文

Threejs_10 光线投射技术完成画布三维事件交互_threejs setfromcamera

threejs setfromcamera

你完成了一个threejs的模型之后,里面有很多东西,你咋知道你点击的是哪个呢??如何触发你点击的事件呢?再canvas画布中可不能和html事件一样直接使用e.target来完成了哦。如何做到呢?

光线投射实现三维定位

方法思想

方法就是从点击的地方创造一条虚拟的从相机射入的射线,来计算这条射线是否穿过了什么几何体,穿过了几个,然后通过方法获取到穿过物体的属性。

1.创建三个小球,将其放入场景中

  1. // 创建三个球
  2. const sphere1 = new THREE.Mesh(
  3. new THREE.SphereGeometry(1, 32, 32),
  4. new THREE.MeshBasicMaterial({
  5. color: 0x00ff00,
  6. })
  7. );
  8. sphere1.position.x = -4;
  9. scene.add(sphere1);
  10. const sphere2 = new THREE.Mesh(
  11. new THREE.SphereGeometry(1, 32, 32),
  12. new THREE.MeshBasicMaterial({
  13. color: 0x0000ff,
  14. })
  15. );
  16. scene.add(sphere2);
  17. const sphere3 = new THREE.Mesh(
  18. new THREE.SphereGeometry(1, 32, 32),
  19. new THREE.MeshBasicMaterial({
  20. color: 0xff00ff,
  21. })
  22. );
  23. sphere3.position.x = 4;
  24. scene.add(sphere3);

 如果觉得三个球离得太近 可以把相机的z轴位置调高一点  也就是我们的眼睛靠后一点

  1. camera.position.z = 15;
  2. // 为了看到z轴
  3. camera.position.y = 2;
  4. // 设置x轴
  5. camera.position.x = 2;
  6. //设置相机的焦点 (相机看向哪个点)
  7. camera.lookAt(0, 0, 0);

2.新建射线,新建鼠标向量

  1. // 创建射线
  2. const raycaster = new THREE.Raycaster();
  3. //创建鼠标向量
  4. const mouse = new THREE.Vector2();

使用THREE.Raycaster 方法创建一个射线,鼠标向量用来存储后面得到的坐标值

3. window事件 获取点击到的地方

  1. window.addEventListener("click", (e) => {
  2. console.log(e.clientX, e.clientY);
  3. //设置鼠标向量的xy值
  4. });

4.公式计算出对应的坐标值 传入鼠标向量中

  1. //给window侦听点击事件 获取点击到的地方
  2. window.addEventListener("click", (e) => {
  3. console.log(e.clientX, e.clientY);
  4. //设置鼠标向量的xy值
  5. //设置鼠标向量的xy值
  6. //公式 可以用边框四个点做测试 或者暂时先记住
  7. mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  8. mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  9. });

 公式是为什么可以用四个点测试一下,然后自己思考一下。或者直接套用。得到的x,y的值就是平面像素转换为三维坐标的x,y值。

5.通过鼠标向量更新射线坐标

  1. window.addEventListener("click", (e) => {
  2. console.log(e.clientX, e.clientY);
  3. //设置鼠标向量的xy值
  4. //设置鼠标向量的xy值
  5. //公式 可以用边框四个点做测试 或者暂时先记住
  6. mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  7. mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  8. //通过摄像机和鼠标位置更新射线
  9. raycaster.setFromCamera(mouse, camera);
  10. });

6. 使用raycaster.intersectObjects方法计算物体和射线的焦点

  1. window.addEventListener("click", (e) => {
  2. console.log(e.clientX, e.clientY);
  3. //设置鼠标向量的xy值
  4. //设置鼠标向量的xy值
  5. //公式 可以用边框四个点做测试 或者暂时先记住
  6. mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  7. mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  8. //通过摄像机和鼠标位置更新射线
  9. raycaster.setFromCamera(mouse, camera);
  10. //计算物体和射线的焦点
  11. const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
  12. console.log(intersects);
  13. });

点击空的地方得到的就是一个空数组,点击有球的地方,得到的就是一个数组,数组值中有object属性,代表的就是这个小球的内容,可以通过object属性来设置小球的参数。

7.交互Demo实现

当然 也有可能出现两个的情况,所以说我们这时候只用取数组第一个值,用它来设置就好了。我们现在用他来做一个点击就变成红色的交互效果,要求是第二次点击的时候 要变回原有的颜色。

我们的思路就是需要再点击的时候判断他是否已经变过色了,如果没有变过色,就让他变色,并且将现在的颜色存起来。如果变过色,就让他的颜色变回来。

  1. //给window侦听点击事件 获取点击到的地方
  2. window.addEventListener("click", (e) => {
  3. console.log(e.clientX, e.clientY);
  4. //设置鼠标向量的xy值
  5. //设置鼠标向量的xy值
  6. //公式 可以用边框四个点做测试 或者暂时先记住
  7. mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  8. mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  9. //通过摄像机和鼠标位置更新射线
  10. raycaster.setFromCamera(mouse, camera);
  11. //计算物体和射线的焦点
  12. const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
  13. // console.log(intersects);
  14. if (intersects[0].object._isSelect) {
  15. //设定旧的颜色
  16. intersects[0].object.material.color.set(intersects[0].object._originColor);
  17. intersects[0].object._isSelect = false;
  18. return;
  19. }
  20. //添加一个属性 选中状态
  21. intersects[0].object._isSelect = true;
  22. //将之前的颜色记录下来
  23. intersects[0].object._originColor =
  24. intersects[0].object.material.color.getHex();
  25. //设定新的颜色
  26. intersects[0].object.material.color.set(0xff0000);
  27. });

 全部代码

  1. //导入 threejs
  2. import * as THREE from "three";
  3. //导入轨道控制器
  4. import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
  5. // 创建场景
  6. const scene = new THREE.Scene();
  7. // 创建相机
  8. const camera = new THREE.PerspectiveCamera(
  9. 45, // 视角
  10. window.innerWidth / window.innerHeight, // 宽高比 窗口的宽高进行设置的
  11. 0.1, // 近平面 相机最近最近能看到的物体
  12. 1000 // 远平面 相机最远能看到的物体
  13. );
  14. // 创建渲染器
  15. const renderer = new THREE.WebGLRenderer();
  16. // 设置渲染器的大小 (窗口大小)
  17. renderer.setSize(window.innerWidth, window.innerHeight);
  18. // 将渲染器的dom元素添加到body中
  19. document.body.appendChild(renderer.domElement);
  20. camera.position.z = 15;
  21. // 为了看到z轴
  22. camera.position.y = 2;
  23. // 设置x轴
  24. camera.position.x = 2;
  25. //设置相机的焦点 (相机看向哪个点)
  26. camera.lookAt(0, 0, 0);
  27. //添加世界坐标辅助器 (红色x轴,绿色y轴,蓝色z轴)一个线段 参数为 线段长度
  28. const axesHelper = new THREE.AxesHelper(5);
  29. //添加到场景之中
  30. scene.add(axesHelper);
  31. // 添加轨道控制器 (修改侦听位置) 一般监听画布的事件 不监听document.body
  32. const controls = new OrbitControls(camera, renderer.domElement);
  33. //渲染函数
  34. function animate() {
  35. controls.update();
  36. //请求动画帧
  37. requestAnimationFrame(animate);
  38. //渲染
  39. renderer.render(scene, camera);
  40. }
  41. animate();
  42. //渲染
  43. // 监听窗口的变化 重新设置渲染器的大小 画布自适应窗口
  44. window.addEventListener("resize", () => {
  45. // 重新设置渲染器的大小
  46. renderer.setSize(window.innerWidth, window.innerHeight);
  47. // 重新设置相机的宽高比
  48. camera.aspect = window.innerWidth / window.innerHeight;
  49. // 重新计算相机的投影矩阵
  50. camera.updateProjectionMatrix();
  51. });
  52. // 创建三个球
  53. const sphere1 = new THREE.Mesh(
  54. new THREE.SphereGeometry(1, 32, 32),
  55. new THREE.MeshBasicMaterial({
  56. color: 0x00ff00,
  57. })
  58. );
  59. sphere1.position.x = -4;
  60. scene.add(sphere1);
  61. const sphere2 = new THREE.Mesh(
  62. new THREE.SphereGeometry(1, 32, 32),
  63. new THREE.MeshBasicMaterial({
  64. color: 0x0000ff,
  65. })
  66. );
  67. scene.add(sphere2);
  68. const sphere3 = new THREE.Mesh(
  69. new THREE.SphereGeometry(1, 32, 32),
  70. new THREE.MeshBasicMaterial({
  71. color: 0xff00ff,
  72. })
  73. );
  74. sphere3.position.x = 4;
  75. scene.add(sphere3);
  76. // 创建射线
  77. const raycaster = new THREE.Raycaster();
  78. //创建鼠标向量
  79. const mouse = new THREE.Vector2();
  80. //给window侦听点击事件 获取点击到的地方
  81. window.addEventListener("click", (e) => {
  82. console.log(e.clientX, e.clientY);
  83. //设置鼠标向量的xy值
  84. //设置鼠标向量的xy值
  85. //公式 可以用边框四个点做测试 或者暂时先记住
  86. mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  87. mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  88. //通过摄像机和鼠标位置更新射线
  89. raycaster.setFromCamera(mouse, camera);
  90. //计算物体和射线的焦点
  91. const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
  92. // console.log(intersects);
  93. if (intersects[0].object._isSelect) {
  94. //设定旧的颜色
  95. intersects[0].object.material.color.set(intersects[0].object._originColor);
  96. intersects[0].object._isSelect = false;
  97. return;
  98. }
  99. //添加一个属性 选中状态
  100. intersects[0].object._isSelect = true;
  101. //将之前的颜色记录下来
  102. intersects[0].object._originColor =
  103. intersects[0].object.material.color.getHex();
  104. //设定新的颜色
  105. intersects[0].object.material.color.set(0xff0000);
  106. });
  107. // //给window侦听点击事件 获取点击到的地方
  108. // window.addEventListener("click", (e) => {
  109. // // console.log(e.clientX, e.clientY);
  110. // //设置鼠标向量的xy值
  111. // //公式 可以用边框四个点做测试 或者暂时先记住
  112. // mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
  113. // mouse.y = -((e.clientY / window.innerHeight) * 2 - 1);
  114. // //测试向量坐标是否正确
  115. // // console.log(mouse.x, mouse.y);
  116. // //通过摄像机和鼠标位置更新射线
  117. // raycaster.setFromCamera(mouse, camera);
  118. // //计算物体和射线的焦点
  119. // const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3]);
  120. // if (intersects[0].object._isSelect) {
  121. // //设定旧的颜色
  122. // intersects[0].object.material.color.set(intersects[0].object._originColor);
  123. // intersects[0].object._isSelect = false;
  124. // return;
  125. // }
  126. // //添加一个属性 选中状态
  127. // intersects[0].object._isSelect = true;
  128. // //将之前的颜色记录下来
  129. // intersects[0].object._originColor =
  130. // intersects[0].object.material.color.getHex();
  131. // //设定新的颜色
  132. // intersects[0].object.material.color.set(0xff0000);
  133. // // console.log(intersects);
  134. // });
  135. //3D 光线投射技术 完成3D三维场景中事件交互

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

闽ICP备14008679号