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

个人简介

👀个人主页: 前端杂货铺
开源项目: 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();

完整代码:

<!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官方文档,真心推荐读一读!!

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


参考资料:

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

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/20638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8 segment介绍

1.YOLOv8图像分割支持的数据格式&#xff1a; (1).用于训练YOLOv8分割模型的数据集标签格式如下: 1).每幅图像对应一个文本文件&#xff1a;数据集中的每幅图像都有一个与图像文件同名的对应文本文件&#xff0c;扩展名为".txt"; 2).文本文件中每个目标(object)占一行…

iReport的下载与安装

下载官网&#xff1a;Home - Jaspersoft Community 网盘下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Oy5opY4GxPZ_mllTlBZ-2w 提取码&#xff1a;75do 安装就是双击后一直点击下一步 安装好了之后要配置jdk环境 iReport 目前 并不支持 高版本jdk 只支持…

TQSDRPI开发板教程:UDP收发测试

项目资源分享 链接&#xff1a;https://pan.baidu.com/s/1gWNSA9czrGwUYJXdeuOwgQ 提取码&#xff1a;tfo0 LWIP自环教程&#xff1a;https://blog.csdn.net/mcupro/article/details/139350727?spm1001.2014.3001.5501 在lwip自环的基础上修改代码实现UDP的收发测试。新建一…

嫁接打印:经济与实用的完美结合

在制造领域&#xff0c;寻求经济且好用的技术方案至关重要。而在模具制造中&#xff0c;3D 打印随形水路在提升冷却效率和产品良率方面的卓越表现已得到广泛认同。如何更经济的应用3D打印技术&#xff0c;就不得不说嫁接打印了。 在嫁接打印的制造过程中&#xff0c;产品的一部…

音视频开发—H264 SPS 和 PPS 参数说明

文章目录 序列参数集 (SPS, Sequence Parameter Set)SPS的主要内容&#xff1a; 图像参数集 (PPS, Picture Parameter Set)PPS的主要内容&#xff1a; Slice Header 结构 在H.264视频编码标准中&#xff0c;SPS和PPS是关键的参数集&#xff0c;它们提供了解码所需的各种配置信息…

Pytorch创建张量

文章目录 1.torch.from_numpy()2. torch.zeros()3. torch.ones()4. torch.arange()5. torch.linspace()6. torch.logspace()7. torch.eye()8. torch.empty()9. torch.full()10. torch.complex()10. torch.rand()10. torch.randint()11. torch.randn12. torch.normal()13. torch…

[数据集][目标检测]剪刀石头布检测数据集VOC+YOLO格式1973张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1973 标注数量(xml文件个数)&#xff1a;1973 标注数量(txt文件个数)&#xff1a;1973 标注…

Docker 简介和安装

目录 Docker 是什么 跟普通虚拟机的对比 打包、分发、部署 Docker 部署的优势 Docker 通常用来做什么 重要概念&#xff1a;镜像、容器 安装 镜像加速源 Docker 是什么 Docker 是一个应用打包、分发、部署的工具 你也可以把它理解为一个轻量的虚拟机&#xff0c;它只虚…

SAP揭秘者- SAP PP模块日常常见运维问题之工单入库失败原因分析及快速处理

文章摘要&#xff1a; 无论您是负责SAP实施项目还是负责SAP运维项目&#xff0c;当用户发现有SAP PP模块的各种异常问题的时都需要作为SAP PP顾问的您快速地理解用户提交的问题&#xff0c;并快速地解决这些问题&#xff0c; 上篇文章跟大家聊了基本单位维护错了怎么修改的解决…

ARC学习(2)基本编程模型认识(二)

笔者继续来学习一下arc的编程模型的寄存器信息。 1、core寄存器深入 参数寄存器&#xff1a;r0-r7&#xff0c;8个参数&#xff0c;暂存器&#xff1a;r10-r15保存寄存器&#xff1a;r16-r25 调用函数需要保存的寄存器指针寄存器&#xff1a;gp&#xff08;全局指针&#xff09…

functional函数对象库学习

类模板 std::function 是一种通用多态函数包装器。std::function 的实例能存储、复制及调用任何可复制构造 (CopyConstructible) 的可调用 (Callable) 目标——函数&#xff08;通过其指针&#xff09;、lambda 表达式、bind 表达式或其他函数对象&#xff0c;以及成员函数指针…

FPGA基于DE2-115开发板驱动HC_SR04超声波测距模块|集成蜂鸣器,led和vga提示功能

文章目录 前言一、实验原理二、Verilog文件2.1 时钟分频2.2 超声波测距2.3 超声波驱动 三、实现过程3.1 模块说明3.2 引脚分配 三、演示视频总结参考 前言 环境 硬件 DE2-115 HC-SR04超声波传感器 软件 Quartus 18.1 目标结果 使用DE2-115开发板驱动HC-SR04模块&#xff0…

Windows 下 PostgreSQL 图形化界面安装、配置详解

相信大家对PostgreSQL都不陌生吧&#xff0c;自从MySQL被Oracle所控制后&#xff0c;PostgreSQL就成为了国内去O的首选数据库了&#xff0c;并且PostgreSQL目前不受任何商业公司控制&#xff0c;所以国内很多厂商都是基于PostgreSQL做二次开发来实现数据库自主可控的目标(国内很…

简单模拟实现shell(Linux)

目录​​​​​​​ 前言 展示效果 实现代码 前言 该代码模拟了shell的实现&#xff0c;也就是解析类似于“ls -a -l"的命令&#xff0c;当我们启动我们自己写的shell的可执行程序时&#xff0c;我们输入"ls"的命令&#xff0c;也可以展示出在shell中输入&…

学习笔记——网络参考模型——TCP/IP模型(物理层)

一、TCP/IP模型-物理层 1、数据传输(交换)的形式 (1)电路交换 特点&#xff1a;通信双方独占通信链路。 优点&#xff1a;数据传输时延小&#xff0c;适用于实时通信&#xff1b;数据按序发送&#xff0c;不存在失序问题&#xff1b;适合模拟信号和数字信号传输。 缺点&am…

【前缀和】42. 接雨水

本文涉及知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode42. 接雨水 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&am…

IDEA+MyBatisX根据mapper方法自动添加注解和生成xml方法结构

前提&#xff1a;确保IDEA已安装并启用了MyBatisX插件 在service层写dao或mapper的方法结构&#xff0c;反向生成dao层方法声明&#xff0c;如下&#xff1a; void updateStock(Long skuId, Long wareId, Integer skuNum); 由于该方法传递多个参数&#xff0c;为了让MyBatis识…

心链6----开发主页以及后端数据插入(多线程并发)定时任务

心链 — 伙伴匹配系统 开发主页 信息搜索页修改 主页开发&#xff08;直接list用户&#xff09; 在后端controller层编写接口去实现显示推荐页面的功能 /*** 推荐页面* param request* return*/GetMapping("/recommend")public BaseResponse<List<User>&…

Go-知识并发控制WaitGroup

Go-知识并发控制WaitGroup 1. 认识 WaitGroup2. 基本原理2.1 信号量2.2 数据结构2.3 Add2.4 Wait2.5 Done 3. 小例子3.1 主协程等待子协程执行完成3.2 子协程等待主协程信号3.3 GetFirst 4. 总结 gitio: https://a18792721831.github.io/ 1. 认识 WaitGroup WaitGroup 是Go 应…

公网IP地址如何查询?

公网IP地址是指在互联网中可以被全球范围内的设备访问的IP地址。在网络通信中&#xff0c;公网IP地址扮演着重要的角色&#xff0c;它可以标识设备在互联网中的位置。查询公网IP地址是一种常见的网络管理需求&#xff0c;因为它能够提供网络设备的准确位置信息&#xff0c;方便…