Three.js——tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器

2024-06-08 1707阅读

个人简介

👀个人主页: 前端杂货铺

⚡开源项目: rich-vue3 (基于 Vue3 + TS + Pinia + Element Plus + Spring全家桶 + MySQL)

🙋‍♂️学习方向: 主攻前端方向,正逐渐往全干发展

📃个人状态: 研发工程师,现效力于中国工业软件事业

🚀人生格言: 积跬步至千里,积小流成江海

🥇推荐学习:🍖开源 rich-vue3 🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2/3项目实战 🥝Node.js实战 🍒Three.js

🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

内容参考链接
WebGL专栏WebGL 入门
Three.js(一)创建场景、渲染三维对象、添加灯光、添加阴影、添加雾化
Three.js(二)scene场景、几何体位置旋转缩放、正射投影相机、透视投影相机
Three.js(三)聚光灯、环境光、点光源、平行光、半球光
Three.js(四)基础材质、深度材质、法向材质、面材质、朗伯材质、Phong材质、着色器材质、直线和虚线、联合材质
Three.js(五)Three.js——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字

文章目录

    • 前言
    • 一、Tween动画
    • 二、点击选取对象
    • 三、加载外部文件
    • 四、使用相机控制器
    • 总结

      前言

      大家好,这里是前端杂货铺。

      上篇文章我们学习了 二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字。接下来,我们继续我们 three.js 的学习!

      在学习的过程中,如若需要深入了解或扩展某些知识,可以自行查阅 => three.js官方文档。


      一、Tween动画

      Tween.js是一个轻量级的 JavaScript 库,可以创建平滑的动画和过渡效果。

      下面,我们设置一个不间断重复的,每两秒进行重新动画的场景。

      核心代码:

      new TWEEN.Tween(cube.rotation).to({
          x: cube.rotation.x + 2,
          y: cube.rotation.y + 2,
          z: cube.rotation.z + 2,
      }, 2000).start().repeat(Infinity);
      TWEEN.update();
      

      完整代码:

      
      
          
          
          
          Document
          *{ margin: 0; padding: 0;}
          
          
      
      
      
          // 创建场景
          const scene = new THREE.Scene();
          // 创建相机 视野角度FOV、长宽比、近截面、远截面
          const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
          // 设置相机位置
          camera.position.set(0, 0, 20);
          // 创建渲染器
          const renderer = new THREE.WebGLRenderer();
          // 设置渲染器尺寸
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
          // 添加立方体
          const cubeGeometry = new THREE.BoxGeometry(3, 3, 3);
          // 创建立方体材质
          const lambert = new THREE.MeshLambertMaterial({
              color: 0xff0000
          });
          const basic = new THREE.MeshBasicMaterial({
              wireframe: true
          });
          const cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, [
              lambert, basic
          ]);
          // 添加到场景
          scene.add(cube);
          // 添加灯光
          const spotLight = new THREE.SpotLight(0xffffff);
          spotLight.position.set(-10, 10, 90);
          scene.add(spotLight);
          new TWEEN.Tween(cube.rotation).to({
              x: cube.rotation.x + 2,
              y: cube.rotation.y + 2,
              z: cube.rotation.z + 2,
          }, 2000).start().repeat(Infinity);
          const animation = () => {
              TWEEN.update();
              // 渲染
              renderer.render(scene, camera);
              requestAnimationFrame(animation);
          }
          animation();
      
      
      
      

      tween动画


      二、点击选取对象

      通过鼠标点击获取x, y坐标,进而计算出归一化坐标。之后通过光线投射进行物体的拾取。

      Raycaster 这个类用于进行光线投射。光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。

      new THREE.Raycaster( origin : Vector3, direction : Vector3, near : Float, far : Float )
      
      参数名称描述
      origin光线投射的原点向量
      direction向射线提供方向的方向向量,应当被标准化
      near返回的所有结果比 near 远。near 不能为负值,其默认值为 0
      far返回的所有结果都比far近。far不能小于near,其默认值为Infinity(正无穷)
      
      
          
          
          
          Document
          *{ margin: 0; padding: 0;}
          
          
      
      
      
          // 创建场景
          const scene = new THREE.Scene();
          // 创建相机 视野角度FOV、长宽比、近截面、远截面
          const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
          // 设置相机位置
          camera.position.set(0, 0, 20);
          // 创建渲染器
          const renderer = new THREE.WebGLRenderer();
          // 设置渲染器尺寸
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
          // 添加立方体
          const cubeGeometry = new THREE.BoxGeometry(2, 2, 2);
          // 创建立方体材质
          const lambert = new THREE.MeshLambertMaterial({
              color: 0xff0000
          });
          const cube = new THREE.Mesh(cubeGeometry, lambert);
          cube.rotation.set(0.4, 0.4, 0);
          cube.position.x = -2;
          // 添加到场景
          cube.name = 'cube';
          scene.add(cube);
          const sphereGeometry = new THREE.SphereGeometry(2, 10, 10);
          const sphere = new THREE.Mesh(sphereGeometry, lambert);
          sphere.position.x = 4;
          sphere.name = 'sphere';
          scene.add(sphere);
          // 添加灯光
          const spotLight = new THREE.SpotLight(0xffffff);
          spotLight.position.set(-10, 10, 90);
          scene.add(spotLight);
          document.onclick = function (event) {
              // 归一化坐标(将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1))
              const x = (event.clientX / window.innerWidth) * 2 - 1;
              const y = -(event.clientY / window.innerHeight) * 2 + 1;
              // 创建设备坐标(三维)
              const standardVector = new THREE.Vector3(x, y, 0.5);
              // 转化为世界坐标 (将此向量 (坐标) 从相机的标准化设备坐标 (NDC) 空间投影到世界空间)
              const worldVector = standardVector.unproject(camera);
              // 做序列化
              const ray = worldVector.sub(camera.position).normalize();
              // 实现点击选中
              // 创建一个射线发射器,用来发射一条射线
              const raycaster = new THREE.Raycaster(camera.position, ray);
              // 返回射线碰撞到的物体
              const intersects = raycaster.intersectObjects(scene.children, true);
              let point3d = null;
              if (intersects.length) {
                  point3d = intersects[0];
              }
              if (point3d) {
                  console.log(point3d.object.name);
              }
          }
          const animation = () => {
              // 渲染
              renderer.render(scene, camera);
              requestAnimationFrame(animation);
          }
          animation();
      
      
      
      

      raycaster光线投射


      三、加载外部文件

      加载外部文件,可以使用 MTL 加载器来实现。

      MTLLoader 一个用于加载 .mtl 资源的加载器,由 OBJLoader 在内部使用。

      材质模版库(MTL)或 .MTL 文件格式是 .OBJ 的配套文件格式, 用于描述一个或多个 .OBJ 文件中物体表面着色(材质)属性。

      MTLLoader( loadingManager : LoadingManager )
      

      接下来,我们加载一个城市模型

      
      
          
          
          
          Document
          *{ margin: 0; padding: 0;}
          
          
          
          
      
      
      
          // 创建场景
          const scene = new THREE.Scene();
          // 创建相机 视野角度FOV、长宽比、近截面、远截面
          const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
          // 设置相机位置
          camera.position.set(0, 300, 400);
          camera.lookAt(new THREE.Vector3(0, 0, 0));
          // 创建渲染器
          const renderer = new THREE.WebGLRenderer();
          // 设置渲染器尺寸
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
          // 添加灯光
          const spotLight = new THREE.SpotLight(0xffffff);
          spotLight.position.set(2000, 8000, 4000);
          scene.add(spotLight);
          const loader = new THREE.OBJMTLLoader();
          // PS:想要文件的加群获取...
          loader.load('../assets/models/city.obj', '../assets/models/city.mtl', (mesh) => {
              scene.add(mesh);
          })
          const animation = () => {
              // 渲染
              renderer.render(scene, camera);
              requestAnimationFrame(animation);
          }
          animation();
      
      
      
      

      Three.js——tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器


      四、使用相机控制器

      相机控制器有很多种,它的作用是使得相机围绕目标进行不同类型的运动。

      接下来,我们使用 轨迹球控制器、第一人称控制器、飞行控制器、翻滚控制器和轨道控制器 查看一下效果。

      
      
          
          
          
          Document
          *{ margin: 0; padding: 0;}
          
          
          
          
          
          
          
          
          
          
          
          
          
          
      
      
      
          const clock = new THREE.Clock();
          // 创建场景
          const scene = new THREE.Scene();
          // 创建相机 视野角度FOV、长宽比、近截面、远截面
          const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
          // 设置相机位置
          // camera.position.set(0, 300, 400);
          // camera.position.set(100, 30, 0);
          camera.position.set(100, 100, 0);
          camera.lookAt(new THREE.Vector3(0, 0, 0));
          // 轨迹球控件
          // const trackball = new THREE.TrackballControls(camera);
          // 第一人称控件
          // const controls = new THREE.FirstPersonControls(camera);
          // controls.lookSpeed = 0.2;
          // 飞行控件
          // const controls = new THREE.FlyControls(camera);
          // controls.rollSpeed = 0.5;
          // 翻滚控件
          // const controls = new THREE.RollControls(camera);
          // 轨道控件
          const controls = new THREE.OrbitControls(camera);
          // 创建渲染器
          const renderer = new THREE.WebGLRenderer();
          // 设置渲染器尺寸
          renderer.setSize(window.innerWidth, window.innerHeight);
          document.body.appendChild(renderer.domElement);
          // 添加灯光
          const spotLight = new THREE.SpotLight(0xffffff);
          spotLight.position.set(2000, 8000, 4000);
          scene.add(spotLight);
          const loader = new THREE.OBJMTLLoader();
          loader.load('../assets/models/city.obj', '../assets/models/city.mtl', (mesh) => {
              scene.add(mesh);
          })
          const animation = () => {
              // trackball.update();
              controls.update(clock.getDelta());
              // 渲染
              renderer.render(scene, camera);
              requestAnimationFrame(animation);
          }
          animation();
      
      
      
      

      下面,我们以轨道控制器为例,看一下具体的呈现效果:

      three.js 使用相机控制器


      总结

      本篇文章我们讲解了几种常见几何体的基本使用,包括 tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器。

      更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!

      好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!


      参考资料:

      1. Three.js 官方文档
      2. WebGL+Three.js 入门与实战【作者:慕课网_yancy】

      Three.js——tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器


VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]