news 2026/5/2 2:57:17

第四部分-模型与动画——19. 模型动画

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第四部分-模型与动画——19. 模型动画

19. 模型动画

1. 概述

模型动画是通过 AnimationMixer 控制模型骨骼动画或变形动画的系统。它支持播放、混合、淡入淡出等高级动画控制功能。

┌─────────────────────────────────────────────────────────────┐ │ 模型动画体系 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 核心类 │ │ ├── AnimationMixer:动画混合器 │ │ ├── AnimationClip:动画剪辑 │ │ ├── AnimationAction:动画动作 │ │ └── AnimationObjectGroup:动画对象组 │ │ │ │ 动画控制 │ │ ├── play():播放动画 │ │ ├── pause():暂停动画 │ │ ├── stop():停止动画 │ │ ├── reset():重置动画 │ │ ├── fadeIn():淡入 │ │ ├── fadeOut():淡出 │ │ └── crossFadeTo():交叉淡变 │ │ │ └─────────────────────────────────────────────────────────────┘

2. AnimationMixer

2.1 基本用法

import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';constmixer=newTHREE.AnimationMixer(model);// 获取动画剪辑constclip=model.animations[0];// 创建动画动作constaction=mixer.clipAction(clip);// 播放动画action.play();// 更新动画(在动画循环中)functionanimate(deltaTime){mixer.update(deltaTime);}

2.2 属性详解

constmixer=newTHREE.AnimationMixer(model);// 时间缩放(速度)mixer.timeScale=1.0;// 当前时间mixer.time=0;// 是否正在更新mixer.enabled=true;// 获取所有动作constactions=mixer._actions;

2.3 方法详解

// 剪辑动作constaction=mixer.clipAction(clip);// 停止所有动作mixer.stopAllAction();// 获取动作constexistingAction=mixer.existingAction(clip);// 获取时间缩放consttimeScale=mixer.getTimeScale();// 设置时间缩放mixer.setTimeScale(1.5);// 更新动画mixer.update(deltaTime);

3. AnimationClip

3.1 属性详解

constclip=model.animations[0];// 动画名称clip.name='walk';// 持续时间(秒)clip.duration=2.0;// 帧率clip.fps=30;// 轨道数组clip.tracks=[];

3.2 创建动画剪辑

import{AnimationClip,VectorKeyframeTrack,NumberKeyframeTrack}from'three';// 位置动画constpositionTrack=newVectorKeyframeTrack('.position',[0,1,2],[0,0,0,2,0,0,0,0,0]);// 旋转动画constrotationTrack=newVectorKeyframeTrack('.rotation',[0,1,2],[0,0,0,0,Math.PI,0,0,0,0]);// 创建剪辑constclip=newAnimationClip('myAnimation',2,[positionTrack,rotationTrack]);

4. AnimationAction

4.1 属性详解

constaction=mixer.clipAction(clip);// 是否正在播放action.isRunning=true;// 是否暂停action.paused=false;// 是否启用action.enabled=true;// 时间缩放action.timeScale=1.0;// 重复次数(Infinity 无限循环)action.repetitions=Infinity;// 循环模式// THREE.LoopRepeat - 重复播放// THREE.LoopOnce - 播放一次// THREE.LoopPingPong - 来回播放action.loop=THREE.LoopRepeat;// 权重(混合强度)action.weight=1.0;// 淡入时间action.fadeInTime=0.5;// 淡出时间action.fadeOutTime=0.5;

4.2 方法详解

// 播放action.play();// 暂停action.pause();// 停止action.stop();// 重置action.reset();// 淡入action.fadeIn(duration);// 淡出action.fadeOut(duration);// 交叉淡变到另一个动作constwalkAction=mixer.clipAction(walkClip);construnAction=mixer.clipAction(runClip);walkAction.crossFadeTo(runAction,0.5);// 设置循环action.setLoop(THREE.LoopRepeat,Infinity);// 设置持续时间action.setDuration(2);// 从指定时间开始action.startAt(1);

5. 动画混合

5.1 权重混合

constidleAction=mixer.clipAction(idleClip);constwalkAction=mixer.clipAction(walkClip);idleAction.play();walkAction.play();// 设置权重idleAction.weight=0.7;walkAction.weight=0.3;// 启用权重混合mixer.addEventListener('loop',(e)=>{// 循环事件});

5.2 淡入淡出

// 从当前动作切换到另一个functionswitchToWalk(){walkAction.reset().fadeIn(0.5).play();idleAction.fadeOut(0.5);}functionswitchToRun(){runAction.reset().fadeIn(0.3).play();walkAction.fadeOut(0.3);}

6. 完整示例

import*asTHREEfrom'three';import{OrbitControls}from'three/examples/jsm/controls/OrbitControls.js';import{GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';constscene=newTHREE.Scene();scene.background=newTHREE.Color(0x111122);constcamera=newTHREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);camera.position.set(5,4,8);camera.lookAt(0,0,0);constrenderer=newTHREE.WebGLRenderer({antialias:true});renderer.setSize(window.innerWidth,window.innerHeight);renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);constcontrols=newOrbitControls(camera,renderer.domElement);controls.enableDamping=true;// 光源constambientLight=newTHREE.AmbientLight(0x404040,0.5);scene.add(ambientLight);constdirectionalLight=newTHREE.DirectionalLight(0xffffff,1);directionalLight.position.set(5,10,7);directionalLight.castShadow=true;scene.add(directionalLight);// 辅助对象constaxesHelper=newTHREE.AxesHelper(5);scene.add(axesHelper);constgridHelper=newTHREE.GridHelper(10,20);scene.add(gridHelper);// 创建带动画的简单模型constgroup=newTHREE.Group();// 身体constbodyGeo=newTHREE.BoxGeometry(1,1.2,0.8);constbodyMat=newTHREE.MeshStandardMaterial({color:0x44aa88,metalness:0.5,roughness:0.3});constbody=newTHREE.Mesh(bodyGeo,bodyMat);body.castShadow=true;group.add(body);// 头部constheadGeo=newTHREE.SphereGeometry(0.6,32,32);constheadMat=newTHREE.MeshStandardMaterial({color:0x88aaff,metalness:0.2,roughness:0.4});consthead=newTHREE.Mesh(headGeo,headMat);head.position.y=0.9;head.castShadow=true;group.add(head);// 手臂constarmGeo=newTHREE.BoxGeometry(0.4,1,0.4);constarmMat=newTHREE.MeshStandardMaterial({color:0x44aa88});constleftArm=newTHREE.Mesh(armGeo,armMat);leftArm.position.set(-0.7,0.5,0);constrightArm=newTHREE.Mesh(armGeo,armMat);rightArm.position.set(0.7,0.5,0);group.add(leftArm,rightArm);scene.add(group);// 创建动画剪辑constmixer=newTHREE.AnimationMixer(group);// 手臂摆动动画constarmPositions=[-0.5,0.5,0,0.5,0.5,0,-0.5,0.5,0];constleftArmTrack=newTHREE.VectorKeyframeTrack('leftArm.position',[0,0.5,1],[-0.7,0.5,0,-0.3,0.5,0,-0.7,0.5,0]);constrightArmTrack=newTHREE.VectorKeyframeTrack('rightArm.position',[0,0.5,1],[0.7,0.5,0,0.3,0.5,0,0.7,0.5,0]);constarmClip=newTHREE.AnimationClip('armSwing',1,[leftArmTrack,rightArmTrack]);constarmAction=mixer.clipAction(armClip);armAction.play();// 上下浮动动画constbodyTrack=newTHREE.VectorKeyframeTrack('.position',[0,0.5,1],[0,0,0,0,0.2,0,0,0,0]);constfloatClip=newTHREE.AnimationClip('float',1,[bodyTrack]);constfloatAction=mixer.clipAction(floatClip);floatAction.play();// 头部旋转动画constheadTrack=newTHREE.VectorKeyframeTrack('head.rotation',[0,0.5,1],[0,0,0,0,0.5,0,0,0,0]);constheadClip=newTHREE.AnimationClip('headRotate',1,[headTrack]);constheadAction=mixer.clipAction(headClip);headAction.play();// GUI 控制importGUIfrom'lil-gui';constgui=newGUI();constanimationFolder=gui.addFolder('动画控制');animationFolder.add(mixer,'timeScale',0,2).name('播放速度');animationFolder.add(armAction,'timeScale',0,2).name('手臂速度');animationFolder.add(floatAction,'timeScale',0,2).name('浮动速度');animationFolder.add(armAction,'weight',0,1).name('手臂权重');animationFolder.add(floatAction,'weight',0,1).name('浮动权重');animationFolder.add({pause:()=>armAction.paused=!armAction.paused},'pause').name('暂停/继续');animationFolder.open();// 地面constplaneGeometry=newTHREE.PlaneGeometry(8,8);constplaneMaterial=newTHREE.MeshStandardMaterial({color:0x336699,side:THREE.DoubleSide});constplane=newTHREE.Mesh(planeGeometry,planeMaterial);plane.rotation.x=-Math.PI/2;plane.position.y=-1;plane.receiveShadow=true;scene.add(plane);letlastTime=0;functionanimate(currentTime){requestAnimationFrame(animate);constdelta=Math.min(0.033,(currentTime-lastTime)/1000);lastTime=currentTime;mixer.update(delta);controls.update();renderer.render(scene,camera);}animate(0);window.addEventListener('resize',onWindowResize,false);functiononWindowResize(){camera.aspect=window.innerWidth/window.innerHeight;camera.updateProjectionMatrix();renderer.setSize(window.innerWidth,window.innerHeight);}

7. 总结

用途
AnimationMixer动画混合器
AnimationClip动画剪辑
AnimationAction动画动作
VectorKeyframeTrack向量关键帧轨道
NumberKeyframeTrack数字关键帧轨道
动画控制方法说明
play()播放动画
pause()暂停动画
stop()停止动画
reset()重置动画
fadeIn()淡入
fadeOut()淡出
crossFadeTo()交叉淡变

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/2 2:56:49

【仅限头部AI中台内部流出】Swoole v5.1+LLM推理服务长连接最佳实践白皮书(含TLS 1.3优化参数表与goroutine泄漏检测脚本)

更多请点击: https://intelliparadigm.com 第一章:Swoole v5.1LLM长连接架构演进与核心挑战 Swoole v5.1 引入了原生协程调度器重构、更细粒度的内存管理及对 HTTP/3 和 QUIC 的实验性支持,为构建高并发、低延迟的 LLM 服务长连接网关提供了…

作者头像 李华
网站建设 2026/5/2 2:42:22

智能代理选择机制:拍卖算法与性能优化实践

1. 智能代理选择机制的核心原理在分布式计算和人工智能系统中,智能代理选择机制扮演着至关重要的角色。这种机制本质上是一个动态资源分配系统,它通过实时评估不同代理的计算能力和成本效益,来决定任务的最佳执行者。想象一下,这就…

作者头像 李华
网站建设 2026/5/2 2:41:38

别再踩坑了!Java自动拆箱装箱的5个隐藏陷阱与避坑指南

Java自动拆箱装箱的5个隐藏陷阱与避坑指南 在Java开发中,自动拆箱(Unboxing)和装箱(Boxing)机制看似简单,却暗藏诸多陷阱。许多经验丰富的开发者也会在不经意间掉入这些坑中,导致程序出现难以察…

作者头像 李华
网站建设 2026/5/2 2:37:01

VisualCppRedist AIO:一站式解决Windows运行库依赖的终极方案

VisualCppRedist AIO:一站式解决Windows运行库依赖的终极方案 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经遇到过打开某个软件或游戏时…

作者头像 李华
网站建设 2026/5/2 2:31:25

为内部知识问答系统集成Taotoken的多模型回答能力

为内部知识问答系统集成Taotoken的多模型回答能力 1. 企业知识库系统的智能化升级需求 现代企业知识管理系统正逐步从静态文档存储转向智能交互式问答。传统Java架构的知识库系统通常采用关键词检索或规则匹配方式回答问题,难以应对复杂语义查询。通过集成Taotoken平…

作者头像 李华