VUE2+THREE.JS 按照行动轨迹移动人物模型并相机视角跟随人物
按照行动轨迹移动人物模型并相机视角跟随人物
- 1. 初始化加载模型
- 2. 开始移动模型
- 3. 人物模型启动
- 4. 暂停模型移动
- 5. 重置模型位置
- 6. 切换区域动画
- 7. 摄像机追踪模型
- 8. 移动模型位置
- 9.动画执行
人物按照上一篇博客所设定的关键点位置,匀速移动
1. 初始化加载模型
// 加载巡航人物模型 callback 动作完成的回调函数
initWalkPerson(callback) {fbxloader("walk").then((obj) => {obj.scale.set(2.5, 2.5, 2.5);obj.name = "person";person = obj;scene.add(obj);//有回调函数 就执行回调函数callback && callback();});
},
2. 开始移动模型
// 开始移动模型
startAnimation() {if (isAnimating) return this.elMessage("当前巡航已开始,请勿多次操作", "error");isAnimating = true;//说明模型已加载完成,无需重复加载,直接执行动画效果if (person) {this.personPositionStart();} else {//人物模型加载完毕后在执行this.initWalkPerson(() => {this.personPositionStart();});}
},
3. 人物模型启动
//人物动画启动
personPositionStart() {personMixer = new THREE.AnimationMixer(person);let AnimationAction = personMixer.clipAction(person.animations[0]);AnimationAction.play();person.position.set(pointArr[0]);scene.getObjectByName("path").material.visible = false; //隐藏行动轨迹动画scene.getObjectByName("person").visible = true;tweenHandlers = [];// 定义速度(单位:单位长度/秒)const speed = 300; // 你可以根据需要调整这个速度值let prevTween = null;let startPos = new THREE.Vector3(...pointArr[0]);for (let i = 1; i < pointArr.length; i++) {// 每次循环设置下一个目标点const endPos = new THREE.Vector3(...pointArr[i]);const newTween = this.createTween(startPos.clone(), endPos, speed);tweenHandlers.push(newTween);if (prevTween) {prevTween.chain(newTween);} else {// 如果是序列中的第一个tween,立即开始动画newTween.start();}// 将此tween存储为下一个tween的'prevTween'prevTween = newTween;// 更新起始点为当前结束点,为下一个循环准备startPos.copy(endPos);}// 开始第一个tween动画if (tweenHandlers.length > 0) {currentTween = tweenHandlers[0];currentTween.start();isAnimating = true;}// 在最后一个Tween结束后执行的动作prevTween.onComplete(() => {// 在动画被标记为完成时才重置位置this.resetPosition();});
},
4. 暂停模型移动
// 暂停模型移动
pauseAnimation() {if (!isAnimating) {this.elMessage("当前巡航未开始", "warning");return;}if (this.isPaused) {// 恢复摄像机状态camera.position.copy(savedCameraPosition);controls.target.copy(savedCameraTarget);controls.update();// 恢复动画tweenHandlers.forEach((tween) => tween.resume());personMixer.timeScale = 1;this.isPaused = false; //设置this.isPaused为falseisAnimating = true;this.elMessage("动画已恢复", "success");this.updateCameraPosition(person, camera, new THREE.Vector3(0, 250, 200));} else {// 保存当前摄像机状态savedCameraPosition = camera.position.clone();savedCameraTarget = controls.target.clone();// 暂停动画tweenHandlers.forEach((tween) => tween.pause());personMixer.timeScale = 0;this.isPaused = true; //设置this.isPaused为truethis.elMessage("动画已暂停", "success");}
},
5. 重置模型位置
// 重置模型位置
resetPosition() {isAnimating = false;this.pauseAnimation();// 将模型从场景中移除scene.getObjectByName("person").visible = false;// 清理动画混合器if (personMixer) {personMixer.uncacheClip(personMixer._actions[0]._clip);personMixer = null;}tweenHandlers.forEach((item) => item.stop());tweenHandlers = [];// 重置动画状态this.isPaused = false;this.tweenArea({ x: -5000, y: 7000, z: 16000 }, { x: 0, y: 0, z: 1 });//显示行动轨迹scene.getObjectByName("path").material.visible = true;
},
6. 切换区域动画
// 切换区域动画
tweenArea(Position, controlsTarget) {// 传递任意目标位置,从当前位置运动到目标位置const p1 = {// 定义相机位置是目标位置到中心点距离的2.2倍x: camera.position.x,y: camera.position.y,z: camera.position.z,};const p2 = {x: Position.x,y: Position.y,z: Position.z,};changeAreaTween = new TWEEN.Tween(p1).to(p2, 1200); // 第一段动画const update = function (object) {camera.rotation.y = (90 * Math.PI) / 180;camera.position.set(object.x, object.y, object.z);controls.target = new THREE.Vector3(controlsTarget.x, controlsTarget.y, controlsTarget.z);// camera.lookAt(lookAt); // 保证动画执行时,相机焦距在中心点controls.enabled = false;controls.update();};changeAreaTween.onUpdate(update);// 动画完成后的执行函数changeAreaTween.onComplete(() => {controls.enabled = true; // 执行完成后开启控制});changeAreaTween.easing(TWEEN.Easing.Quadratic.InOut);changeAreaTween.start();
},
7. 摄像机追踪模型
// 摄像机追踪模型
updateCameraPosition(model, camera, offset) {if (!this.isPaused && isAnimating) {// 添加条件判断const desiredPosition = new THREE.Vector3().copy(model.position).add(offset);camera.position.lerp(desiredPosition, 0.05);camera.lookAt(model.position);}
},
8. 移动模型位置
// 移动模型位置
createTween(startPosition, endPosition, speed) {// 计算起点到终点的距离const distance = startPosition.distanceTo(endPosition);// 使用距离除以速度来计算持续时间const duration = (distance / speed) * 1000; // 持续时间(以毫秒为单位)// 创建并返回一个新的Tween动画return new TWEEN.Tween(startPosition).to({ x: endPosition.x, y: endPosition.y, z: endPosition.z }, duration).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(() => {//相机的相对偏移量,z=-400 在人物模型的后面const relativeCameraOffset = new THREE.Vector3(0, 100, -400);const targetCameraPosition = relativeCameraOffset.applyMatrix4(person.matrixWorld);camera.position.set(targetCameraPosition.x, targetCameraPosition.y, targetCameraPosition.z);//更新控制器的目标为Person的位置const walkerPosition = person.position.clone();controls.target = new THREE.Vector3(walkerPosition.x, 100, walkerPosition.z);// 确保控制器的变更生效controls.update();// 更新模型位置person.position.copy(startPosition);person.lookAt(endPosition);}).onComplete(() => {// 动画完成时,确保模型位置与结束位置相匹配person.position.copy(endPosition);});
},
9.动画执行
全局定义的参数:
let personMixer = null; // 巡航混合器变量
let personClock = new THREE.Clock(); // 巡航计时工具
// 获取巡航时间差
const personDelta = personClock.getDelta();if (personMixer && isAnimating) {personMixer.update(personDelta);
}
TWEEN.update();
相关文章:
VUE2+THREE.JS 按照行动轨迹移动人物模型并相机视角跟随人物
按照行动轨迹移动人物模型并相机视角跟随人物 1. 初始化加载模型2. 开始移动模型3. 人物模型启动4. 暂停模型移动5. 重置模型位置6. 切换区域动画7. 摄像机追踪模型8. 移动模型位置9.动画执行 人物按照上一篇博客所设定的关键点位置,匀速移动 1. 初始化加载模型 //…...
Hadoop YARN组件
1. 请解释Yarn的基本架构和工作原理。 YARN,也被称为"Yet Another Resource Negotiator",是Apache HadoopYARN,也被称为"Yet Another Resource Negotiator",是Apache Hadoop的一部分,它被设计为一…...
Java架构师技术架构路线
目录 1 概论2 如何规划短中长期的技术架构路线图3 如何规划面向未来的架构4 如何修订路线图执行过程中的偏差5 如何落地路线图-阿里系糙快猛之下的敏捷模式想学习架构师构建流程请跳转:Java架构师系统架构设计 1 概论 首先,规划一个短中长期的技术路线图是非常重要的。短中…...
guacamole docker一键部署脚本
前言 在我学习guacamole的过程中发现全网大致有两种方式安装guacamole的方式: 1. 直接安装(下载java环境/mysql/, 修改配置) 2. docker安装(和直接安装类似,需要下载相关环境,然后做配置) 然…...
蓝桥杯算法心得——想吃冰淇淋和蛋糕(dp)
大家好,我是晴天学长,dp题,怎么设计状态很重要,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪 1) .想吃冰淇淋和蛋糕 想吃冰淇淋与蛋糕 输入格式 第一行输入一个整数n。…...
LLM之RAG实战(二):使用LlamaIndex + Metaphor实现知识工作自动化
最先进的大型语言模型(LLM),如ChatGPT、GPT-4、Claude 2,具有令人难以置信的推理能力,可以解锁各种用例——从洞察力提取到问答,再到通用工作流自动化。然而,他们检索上下文相关信息的能力有限。…...
【容器】Docker打包Linux操作系统迁移
0x0 场景 因老服务器操作系统文centos6.5,现要迁移至uos v20 1050a(底层centos8),其中需要迁移的应用组件有: mysql 、tomcat、apachehttpd,因版本跨越太大,导致centos8直接安装无法完全恢复原…...
redis基本数据结构
Redis入门:五大数据类型 文章目录 Redis入门:五大数据类型一.概述二.Redis的基本了解三.Redis五大数据类型1.String (字符串)2.List(列表)3.Set集合(元素唯一不重复)4.Hash集合5.zSet(有序集合) 一.概述 什么是Redis Redis(Remote Dictiona…...
Learning Normal Dynamics in Videos with Meta Prototype Network 论文阅读
文章信息:发表在cvpr2021 原文链接: Learning Normal Dynamics in Videos with Meta Prototype Network 摘要1.介绍2.相关工作3.方法3.1. Dynamic Prototype Unit3.2. 视频异常检测的目标函数3.3. 少样本视频异常检测中的元学习 4.实验5.总结代码复现&a…...
Unity 关于SpriteRenderer 和正交相机缩放
float oldWidth 750f;float oldHeight 1334f;float newWidth Screen.width;float newHeight Screen.height;float oldAspect oldWidth / oldHeight;float newAspect newWidth / newHeight;//水平方向缩放float horizontalCompressionRatio newAspect / oldAspect;//垂直…...
HarmonyOS应用开发者基础认证考试(98分答案)
基于最近大家都在考这个应用开发者基础认证考试,因此出了一期,一样复制word里面搜索做,很快,当然good luck 判断题 Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件。一个应用可以包含一个或多个Ability。 正确(Tr…...
Ubuntu20.04 Kimera Semantic运行记录
Ubuntu20.04 Kimera Semantic 官方bag运行记录 以下基本为官方教程,有部分修改 依赖 sudo apt-get install python3-wstool python3-catkin-tools protobuf-compiler autoconf sudo apt-get install ros-noetic-cmake-modulessudo apt-get install ros-noetic-i…...
服务器RAID系统的常见故障,结合应用场景谈谈常规的维修处理流程
常见的服务器RAID系统故障包括硬盘故障、控制器故障、电源故障、写入错误和热插拔错误。下面结合这些故障的应用场景和常规维修处理流程来详细讨论: 硬盘故障: 应用场景:在服务器RAID系统中,硬盘故障是最常见的问题之一。硬盘可能…...
计算机网络——数据链路层-封装成帧(帧定界、透明传输-字节填充,比特填充、MTU)
目录 介绍 帧定界 PPP帧 以太网帧 透明传输 字节填充(字符填充) 比特填充 比特填充习题 MTU 介绍 所谓封装成帧,就是指数据链路层给上层交付下来的协议数据单元添加帧头和帧尾,使之成为帧。 例如下图所示: …...
MySQL笔记-第03章_基本的SELECT语句
视频链接:【MySQL数据库入门到大牛,mysql安装到优化,百科全书级,全网天花板】 文章目录 第03章_基本的SELECT语句1. SQL概述1.1 SQL背景知识1.2 SQL语言排行榜1.3 SQL 分类 2. SQL语言的规则与规范2.1 基本规则2.2 SQL大小写规范 …...
FTP服务文件上传失败,错误码553的排故过程
本文主要记录文件上传失败,错误码553的排故过程。 1 背景 树莓派通过FTP给嵌入式板卡传输文件,好几套设备,发现有的能传输成功,有的传输不成功。树莓派和嵌入式板卡都一样的,出现问题时感觉很懵。 2 逐项对比 2.1 自…...
音频录制软件哪个好?帮助你找到最合适的一款
音频录制软件是日常工作、学习和创作中不可或缺的一部分。选择一个适合自己需求的录音软件对于确保音频质量和提高工作效率至关重要。可是您知道音频录制软件哪个好吗?本文将深入探讨两种常见的音频录制软件,通过详细的步骤指南,帮助您了解它…...
9.Unity搭建HTTP服务器
搭建HTTP服务器的几种方式 //1.使用别人做好的HTTP服务器软件,一般作为资源服务器时使用该方式(学习阶段建议使用) //2.自己编写HTTP服务器应用程序,一般作为Web服务器 或者 短链接游戏服务器时 使用该方式 使用别人做好的HTTP服…...
C# 热键注册工具类
写在前面 介绍一个验证过的热键注册工具类,使用系统类库user32.dll中的RegisterHotkey函数来实现全局热键的注册。 代码实现 [Flags]public enum KeyModifiers{Alt 1,Control 2,Shift 4,Windows 8,NoRepeat 0x4000}public static class HotKeyHelper{[DllImp…...
nodejs微信小程序+python+PHP天天网站书城管理系统的设计与实现-计算机毕业设计推荐
目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…...
Hive环境准备[重点学习]
1.前提启动hadoop集群 hadoop在统一虚拟机中已经配置了环境变量 启动hdfs和yarn集群 命令:start-all.sh [rootnode1 /]# start-all.sh启动mr历史服务 命令:mapred --daemon start historyserver [rootnode1 /]# mapred --daemon start historyserver检查服务 命令:jps [r…...
软件工程 室友整理
如何理解结构化需求分析方法的基本思想; 结构化分析方法是一种面向数据流的需求分析方法,其中数据作为独立实体转换,数据建模定义数据的属性和关系,操作数据的处理建模表名当做数据在系统流动时候处理如何转换数据 简述面向对象的基本概念&a…...
JVM==>图解字节码指令
一,原始代码 我们来看一下执行这段代码的具体流程 那执行这段代码中 JVM就会把已经编译好的.class文件加载到内存中,交给CPU运行 1)常量池载入运行时常量池 我们发现 10 并没有被存入常量池中, 这是因为short范围以内的数字不会…...
MISRA C 2012 标准浅析
MISRA(The Motor Industry Software Reliability Association),汽车工业软件可靠性联会; 1994年,英国成立。致力于协助汽车厂商开发安全可靠的软件的跨国协会,其成员包括:AB汽车电子、罗孚汽车、宾利汽车、福特汽车、捷…...
Redis高可用之Sentinel哨兵模式
一、背景与简介 Redis关于高可用与分布式有三个与之相关的运维部署模式。分别是主从复制master-slave模式、哨兵Sentinel模式以及集群Cluster模式。 这三者都有各自的优缺点以及所应对的场景、对应的业务使用量与公司体量。 1、主从master-slave模式 【介绍】 这种模式可以采用…...
AI “自主运行”的计算机概念正逐渐成为现实
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
数据库系统概论期末经典大题讲解(用关系代数进行查询)
今天也是结束的最为密集的考试周,在分析过程中自己也有些许解题的感悟,在此分享出来,希望能帮到大家期末取得好成绩。 一.专门的关系运算 1.选择(σ) 选择操作符用于从关系中选择满足特定条件的元组 例如,…...
算法通关村第十六关-黄金挑战滑动窗口与堆的结合
大家好我是苏麟 , 今天带来一道小题 . 滑动窗口最大值 描述 : 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 题目 : …...
基于jsp的搜索引擎
摘 要 随着互联网的不断发展和日益普及,网上的信息量在迅速地增长,在2004年4月,全球Web页面的数目已经超过40亿,中国的网页数估计也超过了3亿。 目前人们从网上获得信息的主要工具是浏览器,搜索引擎在网络中占有举足轻…...
【Altium designer 20】
Altium designer 20 1. Altium designer 201.1 原理图库1.1.1 上划岗 在字母前面加\在加字母1.1.2 自定义快捷键1.1.3 对齐1.1.4 在原有的电路图中使用封装1.1.5 利用excel创建IC类元件库1.1.6 现有原理图库分类以及调用1.1.7 现有原理图库中自动生成原理图库 1.2 绘制原理图1.…...
做网站加一个定位功能要多少钱/百度seo收费
备份需求和rman备份 oracle数据库的备份相关问答: 1)备份时数据库处于何种状态? 备份时数据库处于OPEN状态,这样数据库可以正常工作。 2)备份的数据备份在什么地方? 备份在本地磁盘。 3)备份的存…...
佛山网站建设no.1/千万不要做手游推广员
摘要 腾兴网为您分享:PHP定时执行程序脚本的例子总结,中邮网院,智宽生活,指南针,弈客围棋等软件知识,以及包牛牛,幼儿园报名表,药品营销策划方案,excel乱码,家年华&#…...
有没有做外贸的网站啊/重庆最新数据消息
“密码”选项是BetterZip解压缩软件的解压密码管理器,其作用是管理解压密码以及在帮助用户使用密码解压压缩软件的。 要使用“密码”选项设置密码管理器,首先需要设置密码管理器主密码。 设置密码管理器主密码 快捷键“Command ,”打开首选…...
住房和城乡建设部网站事故快报/百度搜索引擎属于什么引擎
http://videolectures.net/Top/Computer_Science/Machine_Learning/##tvtt转载于:https://www.cnblogs.com/stoneresearch/archive/2010/08/22/4336500.html...
用国外服务器做赌博网站/厦门网络推广外包
析 构 方 法 封装,有一个叫构造函数 和构造函数对应的还有一种方法叫做析构。 class ren //一个类 是 人类 { public $mingzi ;//成员变量 punction__destruct() //析构方法 { } } 析构方法,有什么做用??什么时…...
新开传奇网站999新服网/百度应用商店官网
2019独角兽企业重金招聘Python工程师标准>>> 常量指针,表述为“是常量的指针”,就是指向常量的指针,关键字 const 出现在 * 左边,表示指针所指向的地址的内容是不可修改的,但指针自身可变。 指针常量&#…...