Introduction to Threejs 24: Animation animation in Threejs

Threejs provides us with a powerful animation system interface API. Through these interfaces, we can easily realize various effects such as object movement, rotation, scaling, color change, transparency change, etc. Today we will learn about the animation in Threejs system.
First of all, let's understand several important components in the Threejs animation system

KeyframeTrack key frame track

A keyframe track (KeyframeTrack) is a timed sequence of keyframes, consisting of a list of times and associated values, used to animate a specific property of an object.

There are always two arrays present in a KeyframeTrack: the times array stores the time values ​​of all the keyframes of the track in order, and the values ​​array contains the corresponding change values ​​of the animation properties.

Each member in the value array belongs to a specific time point, not only a simple number, but also a vector (if it is a position animation) or a quaternion (if it is a rotation animation). So the value array (also a flat array) might be three or four times as long as the time array.

Constructor

KeyframeTrack( name : String, times : Array, values ​​: Array, interpolation : Constant )
name - the identifier of the keyframe track (KeyframeTrack)
times - the time array of the key frame, which is internally converted to Float32Array
values ​​- the time in the time array Array of point-related values, internally converted to Float32Array
interpolation - Interpolation type to use

For the specific properties and methods of KeyframeTrack, please refer to the official documentation, so I won't go into details here.

Commonly used KeyframeTrack subclasses

VectorKeyframeTrack: key frame track of vector type
ColorKeyframeTrack: key frame track of reaction color change
BooleanKeyframeTrack: key frame track of Boolean type NumberKeyframeTrack:
key frame track of digital type
QuaternionKeyframeTrack: key frame track of
quaternion type StringKeyframeTrack: key of string type frame track

AnimationClip animation clip

An AnimationClip is a reusable set of keyframe tracks used to define animations

Constructor

AnimationClip( name : String, duration : Number, tracks : Array )
name - the name of this clip
duration - duration (in seconds). If a negative number is passed, the duration will be calculated from the passed array.
tracks - An array of KeyframeTracks. In AnimationClip, the data of each animation property is stored in a separate KeyframeTrack

Animation Mixer Animation Mixer

An animation mixer is a player for animations of specific objects in the scene. When multiple objects in a scene are animated independently, each object can use the same animation mixer.

Constructor

AnimationMixer( rootObject : Object3D )
rootObject - The object to which the animation played by the mixer belongs

Attributes

.time : Number type; the global mixer time (in seconds; the moment when the mixer is created is recorded as 0 time)
.timeScale : Number type; the scale factor of the global time (mixer time)
Note : Set the time scale of the mixer to 0, later set to 1 to pause/unpause all actions controlled by this mixer.

common method

.clipAction (clip : AnimationClip, optionalRoot : Object3D) : AnimationAction
returns the AnimationAction of the clip parameter passed in, the root object parameter is optional, and the default value is the default root object of the mixer. The first parameter can be an AnimationClip object or the name of an animation clip.

If no action exists that matches the clip and root object parameters passed in, the method will create one. Multiple calls with the same parameters will return the same clip instance.
.update (deltaTimeInSeconds : Number) : Advance the mixer time and update the animation

Usually done in the rendering loop, pass in clock.getDelta scaled according to the mixer's time scale (timeScale)

AnimationAction animation action

AnimationActions is used to control animations stored in AnimationClips. By configuring the AnimationAction, we can decide when to play, pause or stop an AnimationClip in one of the mixers, whether the AnimationClip needs to be played repeatedly and how often, whether to use fading or time scaling, and some other things (such as crossfade and sync).

Constructor

AnimationAction( mixer : AnimationMixer, clip : AnimationClip, localRoot : Object3D )
mixer - the animation
clip - the animation clip saves the animation data in this action
localRoot - the root object for action execution

Note : Usually we don't call this constructor directly, but first instantiate an AnimationAction with AnimationMixer.clipAction, because this method provides caching to improve performance.

animation instance

Through the above introduction, we have learned about several common components of the animation system in Threejs. Next, we create a moving cube and make it move, rotate, scale, and change color through the animation system of threejs to make it move; and the
front The chapters are the same, first build the environment, the code is as follows, the specific details will not be mentioned, there are notes, if you don’t understand, you can read the previous article

Introduce threejs to create scenes, cameras, renderers, etc.

index.html

<body> 
  <script type="importmap">
    {
    
    
      "imports":{
    
    
        "three":"../../three.js/build/three.module.js",
        "three/addons/": "../../three.js/examples/jsm/"
      }
    }
  </script>
  <script type="module" src="./index.js"></script>
</body>

Code in index.js

import * as THREE from 'three'
import {
    
     OrbitControls } from 'three/addons/controls/OrbitControls.js'


// 定义变量
let camera,scene,renderer
let axesHelper
let hesLight,dirLight
let box
let controls

// 初始化场景
initScene()
// 初始化相机
initCamera()
// 初始化辅助轴
initAxesHelper()
// 初始化灯光
initLight()
// 初始化渲染器
initRenderer()
// 循环执行
animate()

// 初始化轨道控制器
initControl()
// 窗体重置
window.addEventListener('resize', function () {
    
    
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
})
function initScene() {
    
    
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x888888)
}

function initCamera() {
    
    
  camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,100)
  camera.position.set(5,5,5)
}

function initAxesHelper() {
    
    
  axesHelper = new THREE.AxesHelper(3)
  scene.add(axesHelper)
}

function initLight() {
    
    
  hesLight = new THREE.HemisphereLight()
  hesLight.intensity = 0.3
  scene.add(hesLight)

  dirLight = new THREE.DirectionalLight()
  dirLight.position.set(5,5,-5)
  scene.add(dirLight)
}

function initControl() {
    
     
  controls = new OrbitControls(camera, renderer.domElement)
}

function initRenderer() {
    
     
  renderer = new THREE.WebGLRenderer({
    
     antialias: true }) 
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(window.innerWidth,window.innerHeight)
  document.body.appendChild(renderer.domElement)
}

function animate() {
    
    
  requestAnimationFrame(animate)
  renderer.render(scene,camera)
}

create cube

// 初始化物体
initMeshes()
function initMeshes() {
    
    
  box = new THREE.Mesh(
    new THREE.BoxGeometry(1,1,1),
    new THREE.MeshLambertMaterial({
    
    color:0x00ff00})
  )
  scene.add(box)
}

create animation

First create an initAnimation() function and call the function, and write animation-related content into the code block

// 创建动画
initAnimation()
function initAnimation() {
    
    
  
}

Create a moving animation

First, let's create a moving animation. Let's define the key frame of the animation. We use VectorKeyframeTrack to create the key frame of the moving animation. Add the following code to initAnimation() to
create the moveKeyFrame key frame

// 移动
  const moveKeyFrame = new THREE.VectorKeyframeTrack(
    '.position',//要控制关键帧的名称
    [0,1,2],// 定义三帧
    [
      0,0,0,//第一帧位置
      5,0,0,//第二帧位置
      0,0,0//第三帧位置
    ]
  )

Define the variable clip and create the animation clip
Define the clip variable at the top of index.js

let clip

Create animation clips in initAnimation()

// 动画剪辑
  clip = new THREE.AnimationClip(
    'Action', //动画名称
    4,//动画持续时间
    [moveKeyFrame]//轨迹
  )

In the above two steps, we created keyframes and animation clips respectively, but these two parts are independent and have no relationship. We need to associate the above keyframes with animation clips, which requires the animation mixer to create
animations Mixer
defines the mixer variable at the top of index.js

let mixer
enableAnimation()

Create the enableAnimation() function, and create an instance of the animation mixer in this function, which receives a parameter and passes the box created above as a parameter

function enableAnimation() {
    
    
  // 通过创建动画混合器实例,实现要做动画的物体与动画关联起来
  mixer = new THREE.AnimationMixer( box )
}

Execute the clipAction() method of the animation mixer. This method receives a parameter and passes the clip created above as a parameter.
It returns the AnimationAction of the clip parameter passed in. Define a variable clipAction to receive the returned AnimationAction

 // 通过动画混合器的clipAction方法,实现动画剪辑AnimationClip与动画混合器的关联
  const clipAction =  mixer.clipAction( clip ) 

Call the play method of AnimationAction to execute the animation

clipAction.play()

The complete code of the enableAnimation() method is as follows

function enableAnimation() {
    
    
  // 通过创建动画混合器实例,实现要做动画的物体与动画关联起来
  mixer = new THREE.AnimationMixer( box )
  // 通过动画混合器的clipAction方法,实现动画剪辑AnimationClip与动画混合器的关联
  const clipAction =  mixer.clipAction( clip )
  // 通过上面两步实现 box和clip的关联
  clipAction.play()
}

Through the above code, we have completed the key frame definition, animation clip creation, animation mixer creation and animation execution code, however, refreshing the browser found that there is no animation process, because we still need to set the animation mixer in the cycle Call the update function in the processing function to update
When executing the update function, it receives a deltaTimeInSeconds parameter, we first create a Threejs built-in clock object

let clock = new THREE.Clock()

Define the variable delta in the animate() method to receive the return value of the getDelta() method of the clock, which returns the time lost since the clock was created to the present

const delta = clock.getDelta() //获取自 .oldTime 设置后到当前的秒数。

Pass the delta as a parameter to the update method of the animation mixer

// 更新mixer,delta 一个时间的概念
  mixer.update(delta)

The complete code in the animate() method is as follows

function animate() {
    
    
  // 获取流失的时间delta
  const delta = clock.getDelta() //获取自 .oldTime 设置后到当前的秒数。
  requestAnimationFrame(animate)
  // 更新mixer,delta 一个时间的概念
  mixer.update(delta)
  renderer.render(scene,camera)
}

So far, we have realized the moving animation of the object, refresh the browser, and check the effect
insert image description here

rotation animation

To realize the rotation animation, you need to define which axis to rotate along first, and define the start angle and end angle of the rotation, and then define the key frame through the key frame track of the QuaternionKeyframeTrack type, the code is as follows

  // 旋转
  const xAxis = new THREE.Vector3(1,0,0) //三维向量,沿x轴
  const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis,0)//起点角度
  const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis,Math.PI)//终点角度
  const rotationKeyFrame = new THREE.QuaternionKeyframeTrack(
    '.quaternion',
    [0,1,2],//三帧
    [
      qInitial.x,qInitial.y,qInitial.z,qInitial.w,//第一帧
      qFinal.x,qFinal.y,qFinal.z,qFinal.w,//第二帧
      qInitial.x,qInitial.y,qInitial.z,qInitial.w//第三帧
    ]
  )

After defining the keyframes, add the keyframes defined above to the AnimationClip

// 动画剪辑
  clip = new THREE.AnimationClip(
    'Action', //动画名称
    4,//动画持续时间
    [moveKeyFrame,rotationKeyFrame]//轨迹
  )

Refresh the browser to see the effect. Now the cube rotates and moves. In
insert image description here
the same way, we can add zoom and color changes. The details are similar to the above code, so I won’t be verbose.
Ok, I will write here this time, if you like it, like it, follow it and collect it

Guess you like

Origin blog.csdn.net/w137160164/article/details/130222892