个人简介
👀个人主页: 前端杂货铺
⚡开源项目: 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——二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字 |
文章目录
前言
大家好,这里是前端杂货铺。
上篇文章我们学习了 二维平面、二维圆、自定义二维图形、立方体、球体、圆柱体、圆环、扭结、多面体、文字。接下来,我们继续我们 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();
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style>*{ margin: 0; padding: 0;}</style> <script src="../lib/three/three.js"></script> <script src="../lib/three/tween.min.js"></script> </head> <body> <script> // 创建场景 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(); </script> </body> </html>
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(正无穷) |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style>*{ margin: 0; padding: 0;}</style> <script src="../lib/three/three.js"></script> <script src="../lib/three/tween.min.js"></script> </head> <body> <script> // 创建场景 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(); </script> </body> </html>
raycaster光线投射
三、加载外部文件
加载外部文件,可以使用 MTL 加载器来实现。
MTLLoader 一个用于加载 .mtl 资源的加载器,由 OBJLoader 在内部使用。
材质模版库(MTL)或 .MTL 文件格式是 .OBJ 的配套文件格式, 用于描述一个或多个 .OBJ 文件中物体表面着色(材质)属性。
MTLLoader( loadingManager : LoadingManager )
接下来,我们加载一个城市模型
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style>*{ margin: 0; padding: 0;}</style> <script src="../lib/three/three.js"></script> <script src="../lib/three/OBJLoader.js"></script> <script src="../lib/three/MTLLoader.js"></script> <script src="../lib/three/OBJMTLLoader.js"></script> </head> <body> <script> // 创建场景 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(); </script> </body> </html>
四、使用相机控制器
相机控制器有很多种,它的作用是使得相机围绕目标进行不同类型的运动。
接下来,我们使用 轨迹球控制器、第一人称控制器、飞行控制器、翻滚控制器和轨道控制器 查看一下效果。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style>*{ margin: 0; padding: 0;}</style> <script src="../lib/three/three.js"></script> <script src="../lib/three/OBJLoader.js"></script> <script src="../lib/three/MTLLoader.js"></script> <script src="../lib/three/OBJMTLLoader.js"></script> <!-- 轨迹球控件 --> <script src="../lib/three/TrackballControls.js"></script> <!-- 第一人称控件 --> <script src="../lib/three/FirstPersonControls.js"></script> <!-- 飞行控件 --> <script src="../lib/three/FlyControls.js"></script> <!-- 翻滚控件 --> <script src="../lib/three/RollControls.js"></script> <!-- 轨道控件 --> <script src="../lib/three/OrbitControls.js"></script> </head> <body> <script> 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(); </script> </body> </html>
下面,我们以轨道控制器为例,看一下具体的呈现效果:
three.js 使用相机控制器
总结
本篇文章我们讲解了几种常见几何体的基本使用,包括 tween动画、光线投射拾取、加载.obj/.mtl外部文件、使用相机控制器。
更多内容扩展请大家自行查阅 => three.js官方文档,真心推荐读一读!!
好啦,本篇文章到这里就要和大家说再见啦,祝你这篇文章阅读愉快,你下篇文章的阅读愉快留着我下篇文章再祝!
参考资料:
- Three.js 官方文档
- WebGL+Three.js 入门与实战【作者:慕课网_yancy】