three SkinnedMesh Sprite / 蒙皮网格 精灵

239 阅读7分钟

SkinnedMesh 是 Three.js 中用于处理可变形网格(通常用于角色模型)的一个类。它允许你为模型添加骨骼动画,使得模型可以根据骨骼的移动和旋转来进行动画效果。
Sprite 是 Three.js 中的一种轻量级的二维图形对象,通常用于表示图像、图标或简单的动画效果。它的主要特点是始终面向相机,非常适合用于制作粒子效果、HUD(抬头显示)、2D 游戏对象等。

SkinnedMesh 有七个属性 七个方法

SkinnedMesh( geometry : BufferGeometry, material : Material ) geometry —— 一个BufferGeometry实例。 material —— (可选)一个Material实例,默认值是一个新的MeshBasicMaterial。

    // 创建几何体函数
    function createGeometry(sizing) {
        // 创建一个圆柱几何体
        const geometry = new THREE.CylinderGeometry(
            5, // 圆柱顶部半径
            5, // 圆柱底部半径
            sizing.height, // 圆柱高度
            8, // 圆柱的分段数量(横向)
            sizing.segmentCount * 3, // 圆柱的高度分段数量(纵向),乘以 3 以增加细节
            true // 是否封闭圆柱的两端
        );
        // 获取几何体的顶点位置属性
        const position = geometry.attributes.position;
        const vertex = new THREE.Vector3(); // 用于存储顶点位置的临时向量
        const skinIndices = []; // 存储骨骼索引
        const skinWeights = []; // 存储骨骼权重
        // 遍历所有顶点
        for (let i = 0; i < position.count; i++) {
            vertex.fromBufferAttribute(position, i); // 从缓冲区获取顶点位置
            const y = (vertex.y + sizing.halfHeight); // 计算相对于中点的 y 坐标
            const skinIndex = Math.floor(y / sizing.segmentHeight); // 计算当前顶点对应的骨骼索引
            const skinWeight = (y % sizing.segmentHeight) / sizing.segmentHeight; // 计算当前顶点在相邻两个骨骼之间的权重
            // 将骨骼索引和权重添加到数组中
            skinIndices.push(skinIndex, skinIndex + 1, 0, 0);
            skinWeights.push(1 - skinWeight, skinWeight, 0, 0);
        }
        // 将骨骼索引和权重设置为几何体的属性
        geometry.setAttribute('skinIndex', new THREE.Uint16BufferAttribute(skinIndices, 4));
        geometry.setAttribute('skinWeight', new THREE.Float32BufferAttribute(skinWeights, 4));
        return geometry; // 返回创建的几何体
    }
    // 创建骨骼函数
    function createBones(sizing) {
        const bones = []; // 存储骨骼的数组
        let prevBone = new THREE.Bone(); // 创建第一个骨骼
        bones.push(prevBone); // 将其添加到骨骼数组中
        prevBone.position.y = -sizing.halfHeight; // 将第一个骨骼放置到圆柱底部
        // 创建剩余的骨骼
        for (let i = 0; i < sizing.segmentCount; i++) {
            const bone = new THREE.Bone(); // 创建新骨骼
            bone.position.y = sizing.segmentHeight; // 将其放置到合适的高度
            bones.push(bone); // 添加到骨骼数组中
            prevBone.add(bone); // 将新骨骼添加为前一个骨骼的子骨骼
            prevBone = bone; // 更新前一个骨骼为当前骨骼
        }
        return bones; // 返回创建的骨骼数组
    }
    // 创建网格函数
    function createMesh(geometry, bones) {
        const material = new THREE.MeshBasicMaterial({
            color: 0x156289, // 网格的颜色
            emissive: 0x072534, // 自发光颜色
            side: THREE.DoubleSide, // 双面渲染
            flatShading: true // 平面阴影
        });
        // 创建一个带有骨骼的网格
        const mesh = new THREE.SkinnedMesh(geometry, material);
        const skeleton = new THREE.Skeleton(bones); // 创建骨骼结构
        mesh.add(bones[0]); // 将第一个骨骼添加到网格
        mesh.bind(skeleton); // 将网格与骨骼绑定
        return mesh; // 返回创建的网格
    }
    // 初始化骨骼和网格的函数
    function initBones() {
        const segmentHeight = 8; // 每个分段的高度
        const segmentCount = 4; // 分段数量
        const height = segmentHeight * segmentCount; // 总高度
        const halfHeight = height * 0.5; // 半高度
        // 尺寸设置对象
        const sizing = {
            segmentHeight: segmentHeight,
            segmentCount: segmentCount,
            height: height,
            halfHeight: halfHeight
        };
        // 创建几何体、骨骼和网格
        const geometry = createGeometry(sizing);
        const bones = createBones(sizing);
        const mesh = createMesh(geometry, bones);
        // 返回创建的网格
        return mesh;
    }
    // 初始化骨骼,创建骨骼网格
    const boneMesh = initBones();
    // 此时 boneMesh 是创建好的网格,可以添加到场景中进行渲染,或用于进一步处理
    scene.add(boneMesh); // 将网格添加到场景中
    console.log(boneMesh); // 输出创建的网格以便调试

属性

  • bindMode : String AttachedBindMode 或 DetachedBindMode。 AttachedBindMode 意味着蒙皮网格与骨架共享相同的世界空间。使用 DetachedBindMode 时情况并非如此,该模式在多个蒙皮网格体之间共享骨架时非常有用。默认为 AttachedBindMode 取值为以下属性列表
    `bindMode`:指定骨骼绑定模式,类型为字符串,取值为 `"attached"``"detached"``bindMatrix`:模型的绑定矩阵,用于计算骨骼动画。
    `bindMatrixInverse`:绑定矩阵的逆矩阵,用于修正骨骼动画。
  • bindMatrix : Matrix4 bindMatrix 是 SkinnedMesh 中的一个 Matrix4 类型属性,用于记录模型在骨骼绑定时的初始变换矩阵。它定义了模型与骨骼之间的初始关系,决定了骨骼动画的变形效果。bindMatrix 是在模型和骨骼绑定时生成的,通过它可以确保骨骼动画正确应用到模型上。
  • bindMatrixInverse : Matrix4 bindMatrixInverseSkinnedMesh 中的一个 Matrix4 类型属性,它是 bindMatrix 的逆矩阵(即 bindMatrix 的反转矩阵)。这个属性在骨骼动画中用于将顶点从绑定的局部空间变换回骨骼动画的局部空间。
  • boundingBox : Box3 boundingBox 是 Three.js 中几何体的一个属性,类型为 Box3,表示模型的三维包围盒。它定义了一个最小的轴对齐的立方体,用于包围模型的所有顶点。boundingBox 通常用于碰撞检测、视锥裁剪以及场景优化等场景。
  • boundingSphere : Sphere boundingSphere 是 Three.js 中几何体的一个属性,类型为 Sphere,表示模型的三维包围球。它是一个能完全包围模型的最小球体,通常用于快速的碰撞检测和视锥裁剪。
  • isSkinnedMesh : Boolean 判断是蒙皮
  • skeleton : Skeleton skeleton 是 Three.js 中的一个属性,类型为 Skeleton,它管理和控制一个 SkinnedMesh 模型的骨骼层级结构。Skeleton 包含了模型的骨骼(bones)和它们的姿态信息,用于实现模型的骨骼动画。

方法

  • applyBoneTransform ( index : Integer, vector : Vector3 ) : Vector3 将与给定索引关联的骨骼变换应用于给定位置向量。返回更新后的向量。在 applyBoneTransform(index: Integer, vector: Vector3): Vector3 方法中,传入的 vector 实际上可以被视为一个 基点参考点
  • bind ( skeleton : Skeleton, bindMatrix : Matrix4 ) : undefined skeleton —— 由一棵Bones树创建的Skeleton。 bindMatrix —— 表示骨架基本变换的Matrix4(4x4矩阵)。 将骨架绑定到一个蒙皮网格上。bindMatrix会被保存到.bindMatrix属性中,其逆矩阵.bindMatrixInverse也会被计算出来。
  • clone () : SkinnedMesh 克隆这个蒙皮
  • computeBoundingBox () : undefined 计算包围盒,在调用这个方法后 boundingBox 包含当前蒙皮的最小包围盒
  • computeBoundingSphere () : undefined 计算包围球,在调用这个方法后 boundingBox 包含当前蒙皮的最小包围球
  • normalizeSkinWeights () : undefined 标准化蒙皮的权重。normalizeSkinWeights() 是 SkinnedMesh 类中的一个方法,主要用于标准化(归一化)骨骼权重。在使用蒙皮动画时,每个顶点可能会受到多个骨骼的影响,而这些影响的强度通常用权重表示。标准化骨骼权重确保了所有权重的总和等于 1,这对于确保动画效果的自然性和一致性至关重要。
  • pose () : undefined 这个方法设置了在“休息”状态下蒙皮网格的姿势(重置姿势)。pose() 方法在 Three.js 的 SkinnedMesh 类中用于设置模型的姿势(即骨骼的状态)。这个方法通常用于在骨骼动画系统中更新骨骼的位置和方向,以便在每一帧渲染中显示正确的动画效果。

Sprite 有三个属性两个方法

material - (可选值)是SpriteMaterial的一个实例。 默认值是一个白色的SpriteMaterial。 创建一个新的Sprite。

// 加载纹理
const textureLoader = new THREE.TextureLoader();
const spriteTexture = textureLoader.load("/path");
// 创建 Sprite 材质
const spriteMaterial = new THREE.SpriteMaterial({ map: spriteTexture });
// 创建 Sprite 对象
const sprite = new THREE.Sprite(spriteMaterial);
// 设置 Sprite 的缩放比例
sprite.scale.set(1, 1, 1); // 默认是 1x1x1
// 添加 Sprite 到场景中
scene.add(sprite);

属性

  • isSprite : Boolean 判断是精灵材质
  • material : SpriteMaterial SpriteMaterial的一个实例,定义了这个对象的外观。默认值是一个白色的SpriteMaterial。
  • center : Vector2 这个精灵的锚点,也就是精灵旋转时,围绕着旋转的点。当值为(0.5,0.5)时,对应着这个精灵的中心点;当值为(0,0)时,对应着这个精灵左下角的点。 其默认值是(0.5,0.5)。

方法

  • copy ( sprite : Sprite ) : this 将前一个Sprite对象的属性复制给当前的这个对象。
  • raycast ( raycaster : Raycaster, intersects : Array ) : undefined 在投射的光线和精灵之前产生交互。Raycaster.intersectObject将会调用这个方法。 在对sprite进行射线投射之前,射线投射必须通过调用Raycaster.setFromCamera()来初始化。