ThreeJS中的动画


参考:https://threejs.org/open in new window

动画类型

动画类型描述
帧动画 (Frame Animation)将一系列图片按照顺序播放,形成动画效果,类似于传统手绘动画。
逐帧动画 (Sprite Animation)通过改变精灵纹理的位置或贴图来模拟运动,常用于游戏中的人物、道具等的动画效果。
骨骼动画 (Skeletal Animation)通过骨骼的动画变化来模拟角色的运动,将角色的形态分解成多个骨骼,并通过调整骨骼的变换来实现动画效果。
形状关键帧动画 (Morph Target Animation)通过调整网格顶点的位置、法线和颜色等属性,来模拟物体的形变和运动,比如角色的面部表情、物体的形变等。
粒子动画 (Particle Animation)通过控制一组小粒子的运动轨迹、大小、透明度等属性,来模拟各种自然现象,比如烟雾、火花、雨滴等。
基于物理引擎的动画 (Physics-based Animation)通过物理引擎模拟物体的运动、碰撞、重力、弹性等物理特性,来实现更加真实的动画效果,常用于游戏中的角色、物体等。

ThreeJS 中的动画类

  1. AnimationMixer

    • 使用格式:const mixer = new AnimationMixer( object : Object3D )
    • 功能:管理和混合场景中的动画数据。
    • 参数说明:
      • object:要添加动画数据的 Object3D 对象。
    • 示例:
      const mixer = new THREE.AnimationMixer(mesh);
      
  2. AnimationClip

    • 使用格式:AnimationClip( name : String, duration : Number, tracks : Array )
    • 功能:表示一个包含一组 AnimationTrack 的动画片段。
    • 参数说明:
      • name:动画片段的名称。
      • duration:动画片段的持续时间(秒)。
      • tracks:包含 AnimationTrack 对象的数组。
    • 示例:
      const clip = THREE.AnimationClip.CreateFromMorphTargetSequence(
        "morph",
        geometry.morphAttributes.position,
        30
      );
      
  3. AnimationAction

    • 使用格式:AnimationAction( mixer : AnimationMixer, clip : AnimationClip, localRoot : Object3D )
    • 功能:表示一个 AnimationClipAnimationMixer 中的播放实例。
    • 参数说明:
      • mixerAnimationMixer 对象。
      • clipAnimationClip 对象。
      • localRoot:本地根对象,动画中的对象将相对于此对象移动。
    • 示例:
      const action = mixer.clipAction(clip);
      
  4. AnimationObjectGroup

    • 使用格式:AnimationObjectGroup( ...objects : Object3D[] )
    • 功能:管理多个对象的动画。
    • 参数说明:
      • objects:要添加到 AnimationObjectGroupObject3D 对象。
    • 示例:
      const group = new THREE.AnimationObjectGroup(mesh1, mesh2);
      const clip = THREE.AnimationClip.CreateFromAction(animationAction);
      clip.tracks.shift(); // 移除第一条跟踪轨迹
      group.clipAction(clip).play(); // 播放动画
      
  5. KeyframeTrack

    • 使用格式:KeyframeTrack( name : String, times : Array, values : Array, interpolation : InterpolationModes )
    • 功能:表示动画的关键帧序列。
    • 参数说明:
      • name:关键帧序列的名称。
      • times:关键帧时间的数组。
      • values:与关键帧相关联的值的数组。
      • interpolation:插值模式,默认为 THREE.InterpolateLinear
    • 示例:
      const times = [0, 1, 2];
      const values = [0, 1, 0];
      const track = new THREE.NumberKeyframeTrack(".opacity", times, values);
      

动画的运行是通过 AnimationMixer 类实现的。当一个模型需要播放动画时,我们需要将模型的动画剪辑(AnimationClip)添加到 AnimationMixer 实例中,然后通过 mixer.clipAction() 方法获取一个动画动作(AnimationAction)实例,调用 play() 方法播放动画,AnimationAction 的更新又通过 AnimationMixer.update() 方法实现。

  • 创建动画剪辑(AnimationClip),并将其包含的动画轨迹(AnimationTrack)绑定到场景中的对象上。
  • 创建动画混合器(AnimationMixer),并将动画剪辑添加到混合器中。
  • 调用混合器的 update 方法,更新当前时间下各个对象的状态。
  • 将更新后的状态应用到场景中的对象上,使动画动起来。
// 使用GLTFLoader加载模型
loader.load("models/gltf/Soldier.glb", function (gltf) {
  // 获取模型
  model = gltf.scene;
  // 将模型添加到场景中
  scene.add(model);

  // 遍历模型内的所有对象
  model.traverse(function (object) {
    // 如果对象是网格,则开启阴影投射
    if (object.isMesh) object.castShadow = true;
  });

  // 创建骨骼辅助对象,用于调试和查看骨骼结构
  skeleton = new THREE.SkeletonHelper(model);
  // 设置骨骼辅助对象为不可见
  skeleton.visible = false;
  // 将骨骼辅助对象添加到场景中
  scene.add(skeleton);

  // 创建面板
  createPanel();

  // 获取模型的动画数组
  const animations = gltf.animations;

  // 创建动画混合器
  mixer = new THREE.AnimationMixer(model);

  // 获取模型的不同动作,并将其加入动画混合器中
  idleAction = mixer.clipAction(animations[0]);
  walkAction = mixer.clipAction(animations[3]);
  runAction = mixer.clipAction(animations[1]);

  // 将不同动作保存在数组中
  actions = [idleAction, walkAction, runAction];

  // 激活所有动作
  activateAllActions();

  // 调用动画循环函数
  animate();
});

function activateAllActions() {
  setWeight(idleAction, settings["modify idle weight"]);
  setWeight(walkAction, settings["modify walk weight"]);
  setWeight(runAction, settings["modify run weight"]);

  actions.forEach(function (action) {
    action.play();
  });
}

function setWeight(action, weight) {
  // 设置动画的权重值
  action.enabled = true; // 启用当前动画
  action.setEffectiveTimeScale(1); // 设置动画播放速度为正常速度
  action.setEffectiveWeight(weight); // 设置动画权重值
}

function animation(){
	let mixerUpdateDelta = clock.getDelta();
	mixer.update( mixerUpdateDelta );
}
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.13.0