• Three开关门


    一. 我们在使用Three想要达成开关门动作时,如何避坑?

     

    图一为我们理想例子

    图二图三为非理想例子

    二. Three开关门如何点击获取该模型?

    1. 我们以双击触发该事件,通过鼠标xy轴在屏幕创建three向量位置;

    2. 将创建屏幕坐标转换为Three场景中的坐标;

    3. 通过THREE.Raycaster发射光线获取到点击模型;

    4. 通过TWEEN动画旋转该模型父级场景(重点为旋转父级场景,自身旋转可就如图二喽)rotationY角度;

    1. document.addEventListener('dblclick', onDocumentMouseDown, false);
    2. // 获取与射线相交的对象数组
    3. const onDocumentMouseDown = (event) => {
    4. event.preventDefault();
    5. //1、先基于我们在屏幕上点击的位置创建一个向量
    6. var vector = new THREE.Vector3(
    7. (event.clientX / window.innerWidth) * 2 - 1,
    8. -(event.clientY / window.innerHeight) * 2 + 1,
    9. 0.5
    10. );
    11. //2、然后用unproject函数将点击位置转换成Thres.js场景中的坐标
    12. vector = vector.unproject(Three.camera);
    13. //3、用THREE.Raycaster对象向点击位置发射光线
    14. var raycaster = new THREE.Raycaster(Three.camera.position, vector.sub(Three.camera.position).normalize());
    15. var intersects = raycaster.intersectObjects(Three.scene.children, true);
    16. var currObj = intersects[0].object; //currObj为点击到的第一个对象
    17. if (currObj.parent.rotation.y == 0) {
    18. new TWEEN.Tween(currObj.parent.rotation)
    19. .to(
    20. {
    21. y: 1.5,
    22. },
    23. 1500
    24. )
    25. .start();
    26. } else {
    27. new TWEEN.Tween(currObj.parent.rotation)
    28. .to(
    29. {
    30. y: 0,
    31. },
    32. 300
    33. )
    34. .start();
    35. }
    36. };

     三. 模型核心场景代码

    1. 重点在于mesh与menGroup;mesh为门模型,menGroup为mesh父级场景;

    1.  门宽为40,模型默认在中心轴上那么中心轴的位置在门20的位置;
    2. 我们建立父级场景menGroup将门mesh包裹;
    3. 父级menGroup向右平移20,此时menGroup中心轴在门右侧门框上,随着父级平移,mesh作为子级也会平移,此时我们将mesh门本身向左平移-20,门又回到了原始位置,但是父级menGroup的中心轴还停留在右侧门框;
    4. 此时参考上边currObj.parent.rotation代码,我们获取到门之后旋转父级,大功告成;
    5. 注意事项:不平移自转为图二,平移计算不对为图三;
    1. // 立方体
    2. const cube = () => {
    3. const cubeSize = 40;
    4. const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, 1);
    5. const cubeMat = new THREE.MeshPhongMaterial({ color: '#8AC' });
    6. const mesh = new THREE.Mesh(cubeGeo, cubeMat); // 创景门模型
    7. mesh.position.set(-cubeSize / 2, 0, 0);
    8. const menGroup = new THREE.Group();
    9. menGroup.position.set(cubeSize, 0, 0);
    10. menGroup.add(mesh);
    11. Three.scene.add(menGroup);
    12. };

     四. react版全部代码

    1. import React, { useRef, useEffect, useMemo } from 'react';
    2. import * as THREE from 'three';
    3. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
    4. import TWEEN from 'tween/tween.js';
    5. const ThreeRoom = () => {
    6. const createDom = useRef(null);
    7. const ThreeModel = useRef({
    8. scene: null,
    9. camera: null,
    10. renderer: null,
    11. controller: null,
    12. });
    13. const Three = ThreeModel.current;
    14. // 相机加载
    15. const cameraInit = () => {
    16. Three.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 2000);
    17. Three.camera.position.set(0, 50, 50);
    18. // Three.camera.lookAt(0, 0, 0);
    19. };
    20. // 渲染器实例
    21. const renderer = () => {
    22. Three.renderer = new THREE.WebGL1Renderer();
    23. Three.renderer.setSize(createDom.current.clientWidth, createDom.current.clientHeight);
    24. Three.renderer.setPixelRatio(window.devicePixelRatio);
    25. Three.renderer.setClearAlpha(0);
    26. Three.renderer.setClearColor('rgb(135,206,250)', 1.0);
    27. Three.renderer.setClearColor(0xffffff, 1.0);
    28. Three.renderer.setClearColor('#428bca', 1.0);
    29. Three.renderer.setClearColor('rgba(135,206,250,0.5)', 1.0);
    30. createDom.current.appendChild(Three.renderer.domElement);
    31. };
    32. // 加载场景
    33. const animate = () => {
    34. requestAnimationFrame(animate);
    35. // if (resizeRendererToDisplaySize(Three.renderer)) {
    36. // Three.camera.aspect = window.innerWidth / window.innerHeight;
    37. // Three.camera.updateProjectionMatrix();
    38. // }
    39. TWEEN.update();
    40. Three.renderer.render(Three.scene, Three.camera);
    41. };
    42. // 立方体
    43. const cube = () => {
    44. const cubeSize = 40;
    45. const cubeGeo = new THREE.BoxGeometry(cubeSize, cubeSize, 1);
    46. const cubeMat = new THREE.MeshPhongMaterial({ color: '#8AC' });
    47. const mesh = new THREE.Mesh(cubeGeo, cubeMat); // 创景门模型
    48. mesh.position.set(-cubeSize / 2, 0, 0);
    49. const menGroup = new THREE.Group();
    50. menGroup.position.set(cubeSize, 0, 0);
    51. menGroup.add(mesh);
    52. Three.scene.add(menGroup);
    53. };
    54. // 加载控制器
    55. const controls = () => {
    56. Three.controller = new OrbitControls(Three.camera, Three.renderer.domElement);
    57. Three.controller.maxDistance = 2000;
    58. };
    59. useEffect(() => {
    60. Three.scene = new THREE.Scene();
    61. cameraInit();
    62. cube();
    63. renderer();
    64. controls();
    65. const light = new THREE.AmbientLight(0xffffff, 1);
    66. Three.scene.add(light);
    67. animate();
    68. document.addEventListener('dblclick', onDocumentMouseDown, false);
    69. }, []);
    70. // 获取与射线相交的对象数组
    71. const onDocumentMouseDown = (event) => {
    72. event.preventDefault();
    73. //1、先基于我们在屏幕上点击的位置创建一个向量
    74. var vector = new THREE.Vector3(
    75. (event.clientX / window.innerWidth) * 2 - 1,
    76. -(event.clientY / window.innerHeight) * 2 + 1,
    77. 0.5
    78. );
    79. //2、然后用unproject函数将点击位置转换成Thres.js场景中的坐标
    80. vector = vector.unproject(Three.camera);
    81. //3、用THREE.Raycaster对象向点击位置发射光线
    82. var raycaster = new THREE.Raycaster(Three.camera.position, vector.sub(Three.camera.position).normalize());
    83. var intersects = raycaster.intersectObjects(Three.scene.children, true);
    84. var currObj = intersects[0].object; //currObj为点击到的第一个对象
    85. if (currObj.parent.rotation.y == 0) {
    86. new TWEEN.Tween(currObj.parent.rotation)
    87. .to(
    88. {
    89. y: 1.5,
    90. },
    91. 1500
    92. )
    93. .start();
    94. } else {
    95. new TWEEN.Tween(currObj.parent.rotation)
    96. .to(
    97. {
    98. y: 0,
    99. },
    100. 300
    101. )
    102. .start();
    103. }
    104. };
    105. return <div style={{ width: '100%', height: '100%' }} id="scene" ref={createDom} />;
    106. };
    107. export default ThreeRoom;

     

  • 相关阅读:
    No7.【spring-cloud-alibaba】用户登录密码加密、密码登录模式添加验证码校验
    PostGIS导入shp文件报错:dbf file (.dbf) can not be opened.
    Kafka学习笔记(二)
    93. 复原 IP 地址
    UVM中uvm_config_db非直线的设置与获取
    分析一下:运营商三网大数据能获取精准客户的原因
    解决迁移到AWS的关键挑战
    华为机考入门python3--(17)牛客17- 坐标移动
    【ARM 嵌入式 编译系列 11.1 -- GCC __attribute__((aligned(x)))详细介绍】
    Windows系统管理二:基本命令
  • 原文地址:https://blog.csdn.net/weixin_42358094/article/details/126285284