[Yugong Series] August 2023 Three.js Topic - Skeletal Animation


foreword

Skeletal animation is a computer animation technique that presents viewers with more realistic animations by breaking down the structure of a virtual model into bones and moving those bones as the animation plays. Skeletal animation is usually created using 3D computer graphics software and can be applied in a variety of animation fields, including game production, film production, visual effects, and more.

1. Skeletal animation

1 Introduction

Three.js is a JavaScript library for creating 3D graphics and animations in web browsers. It provides support for skeletal animation, and you can use the Three.js skeletal system to create complex animation effects.

Skeletal animation is an animation technology based on the skeletal system. By creating multiple joints and bones on the model, and then animating these bones, the animation effect of the model is realized. In Three.js, use the SkinnedMesh and Skeleton classes to implement skeletal animation.

SkinnedMesh is a mesh object with a skeletal system. It contains a Geometry object and a Material object, which can be used to create complex character animations. The Skeleton class represents the skeletal system and contains multiple skeletal nodes. Complex animation effects can be achieved by setting the weight, rotation and offset of bone nodes.

When using Three.js to create skeletal animation, you need to build the skeletal system of the model first, then create SkinnedMesh and Skeleton objects, and associate them. Then, use animation libraries such as Tween.js or manually control the transformation of bone nodes to realize the animation effect of the model.

In short, Three.js provides powerful skeletal animation support, which can be used to create various complex animation effects.

2. Concepts related to skeletal animation

2.1 SkinnedMesh skeleton network model

SkinnedMesh is an important concept in Three.js, it can be used to simulate the animation of dynamic objects, such as characters, animals or robots. SkinnedMesh is based on skeletal animation. Its basic principle is to divide a 3D model into multiple parts, then define a bone and a weight for each part, and change the shape and animation of the model by changing the position and angle of the bones.

Specifically, SkinnedMesh consists of the following components:

  1. Geometry: Describes information such as the shape, structure, and texture of the model.

  2. Skeleton (skeleton): A hierarchical structure composed of multiple Bone (skeleton), used to describe the dynamic changes of the model.

  3. Material: Define information such as the surface color, texture, and lighting of the model.

  4. Animations (animation): Define the dynamic behavior of the model, including movement, expression and pose, etc.

SkinnedMesh controls the shape and animation of the model by applying bones and weights to the geometry. Each vertex is assigned to one or more bones, and their corresponding weights are assigned, which determine the degree of influence each bone has on the vertex. When the positions and angles of the bones change, the shape of the model changes accordingly, enabling dynamic animation effects.

2.2 Bone bones and joints

In Three.js, Bone (skeleton) is an object used to control the deformation animation of the mesh model. Bone usually appears as part of a bone hierarchy, which includes multiple bone objects that together make up a skeleton.

Every Bone object has a local coordinate system that defines its position and orientation relative to its parent bone, or base bone (if it is the root bone). The Bone object also includes a weight property, which is used to bind the vertices in the Mesh object, so that when the bone is rotated and transformed, the vertices can be moved accordingly.

Bone objects can also contain child bones. These child bones are connected to the parent bone's local coordinate system and move relative to each other when the parent bone moves. These subbones can be used to create more complex deformation animations, such as the bending of a character's arms and legs.

In Three.js, you can use the Skeleton object to manage Bone objects and their bone hierarchy. Skeleton objects can also set skin weights to bind vertices to bones.

2.2 Skeleton skeleton

Skeleton is an animated object in Three.js, which is composed of bones and joints of bones, and can move and rotate on the screen. Skeleton implements skeletal animation by applying animation to each bone.

When using the Skeleton object in Three.js, you need to create a SkinnedMesh object that contains the Mesh object and the Skeleton object. The SkinnedMesh object connects the mesh to the bone, allowing skeletal animation to be applied to the mesh. After creating the SkinnedMesh object, add the bones and mesh to the Skeleton object.

The Skeleton object has many methods that can be used to control the animation and transformation of bones. For example, the updateMatrixWorld() method can update the global transformation matrix of bones and meshes, and the applyMatrix() method can apply transformation matrices to bones and meshes.

Use Skeleton objects to create very complex animations, such as character animations, driver animations, etc.

3. Case

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    *{
      
      
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>

</body>
</html>

<script type="module">
  import * as THREE from 'https://cdn.skypack.dev/[email protected]';
  const clock = new THREE.Clock()
  // 创建一个场景
  const scene = new THREE.Scene();

  // 创建一个相机 视点
  const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
  // 设置相机的位置
  camera.position.set(100,100,0);
  camera.lookAt(new THREE.Vector3(0,0,0));


  // 创建一个渲染器
  const renderer = new THREE.WebGLRenderer();
  // 设置渲染器尺寸
  renderer.setSize(window.innerWidth, window.innerHeight);

  document.body.appendChild(renderer.domElement);

  // 添加灯光
  const spotLight = new THREE.SpotLight(0xffffff);
  spotLight.position.set(2000,8000,4000);
  scene.add(spotLight);

  // 圆柱体
  const geometry = new THREE.CylinderGeometry(2, 2, 40, 8, 12)

  const material = new THREE.MeshPhongMaterial();

  // 蒙皮 - 皮肤
  const mesh = new THREE.SkinnedMesh(geometry, material)
  scene.add(mesh);

  // 首先,创建一个起点. 创建骨骼系统
  let b1 = new THREE.Bone();
  b1.position.set(0, -20, 0);

  let b2 = new THREE.Bone();
  b1.add(b2)
  b2.position.set(0, 10, 0);

  let b3 = new THREE.Bone();
  b2.add(b3)
  b3.position.set(0, 10, 0)

  let b4 = new THREE.Bone();
  b3.add(b4)
  b4.position.set(0, 10, 0)

  let b5 = new THREE.Bone();
  b4.add(b5)
  b5.position.set(0, 10, 0)

  // 创建骨架
  const skeleton = new THREE.Skeleton([b1, b2, b3, b4, b5])
  mesh.add(b1)
  mesh.bind(skeleton)

  // 添加权重   设置的就是蒙皮的权重,  顶点的蒙皮索引
  const index = [] // 索引
  const weight = [] // 权重

  const arr = geometry.attributes.position.array;
  for (let i = 0; i < arr.length; i += 3) {
      
      
    const y = arr[i + 1] + 20

    // const index = Math.floor(y / 10);
    const weightValue = (y % 10) / 10

    index.push(Math.floor(y / 10), Math.floor(y / 10) + 1, 0, 0)
    weight.push(1 - weightValue, weightValue, 0, 0);
  }
  geometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(index, 4));
  geometry.setAttribute('skinWeight', new THREE.Float32BufferAttribute(weight, 4));

  let step = 0.1;
  const animation = () => {
      
      
    // 渲染
    renderer.render(scene, camera);

    // 添加边界
    if (
      mesh.skeleton.bones[0].rotation.x > 0.3 ||
      mesh.skeleton.bones[0].rotation.x < -0.3
    ) {
      
      
      step = -step
    }

    for (let i = 0; i < mesh.skeleton.bones.length; i++) {
      
      
      mesh.skeleton.bones[i].rotation.x += step * Math.PI / 180;
    }

    requestAnimationFrame(animation);
  }
  animation()
</script>

insert image description here

Guess you like

Origin blog.csdn.net/aa2528877987/article/details/132248541