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技术可行性:…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...