🎯 glTF 是什么
glTF (GL Transmission Format) 是 Khronos Group 开发的 3D 场景和模型的标准格式,被称为 "3D 界的 JPEG"。
📦 文件类型
1️⃣ glTF 的三种格式
🎭 动画绑定原理
核心概念
{
"nodes": [...] // 骨骼节点
"meshes": [...] // 网格模型
"skins": [...] // 蒙皮(绑定骨骼和模型)
"animations": [...] // 动画数据
}🔗 动画绑定流程
1️⃣ 定义骨骼层级 (nodes)
"nodes": [
{
"name": "Actor", // 根节点
"children": [1, 2, 3] // 子节点索引
},
{
"name": "mixamorig:Hips", // 骨盆骨骼
"translation": [0.002, 0.989, -0.001],
"rotation": [-0.031, -0.046, -0.029, 0.998],
"children": [4, 47, 51] // 脊柱、右腿、左腿
},
{
"name": "mixamorig:Spine", // 脊柱
"translation": [0, 0.099, -0.012],
"rotation": [0.029, 0.012, 0.022, 0.999],
"children": [5] // 上脊柱
}
// ... 更多骨骼
]骨骼树结构:
Actor (根)
└── Hips (骨盆)
├── Spine (脊柱)
│ └── Spine1 → Spine2 → Neck → Head
├── RightUpLeg → RightLeg → RightFoot
└── LeftUpLeg → LeftLeg → LeftFoot2️⃣ 蒙皮绑定 (skins)
将网格顶点绑定到骨骼上:
"skins": [
{
"name": "skeleton #0",
"skeleton": 0, // 根骨骼节点索引
"joints": [0, 3, 4, 5, ...], // 参与动画的骨骼索引
"inverseBindMatrices": 16 // 初始绑定姿态的逆矩阵
}
]作用:
告诉每个顶点受哪些骨骼影响
通过权重混合多个骨骼的变换
3️⃣ 动画通道 (animations)
定义每个骨骼在不同时间的位置、旋转、缩放:
"animations": [
{
"name": "Standard_Walk", // 走路动画
"channels": [
{
"sampler": 0, // 使用哪个采样器
"target": {
"node": 3, // 目标骨骼(Hips)
"path": "translation" // 动画类型:位置
}
},
{
"sampler": 1,
"target": {
"node": 3,
"path": "rotation" // 动画类型:旋转
}
}
// ... 每个骨骼的 translation、rotation、scale
],
"samplers": [
{
"input": 18, // 时间数据索引
"output": 19 // 位置数据索引
}
]
}
]🎬 动画播放过程
流程图
1. 加载 glTF 文件
↓
2. 解析骨骼结构 (nodes)
↓
3. 创建蒙皮 (skins) → 绑定顶点到骨骼
↓
4. 读取动画数据 (animations)
↓
5. 每帧更新:
a. 根据时间计算每个骨骼的变换矩阵
b. 通过蒙皮权重影响顶点位置
c. 重新渲染模型📊 数据访问示例
时间轴数据 (accessor)
"accessors": [
{
"bufferView": 6,
"componentType": 5126, // FLOAT
"count": 36, // 36 个关键帧
"max": [1.16666663], // 动画时长 1.17 秒
"min": [0.0],
"type": "SCALAR", // 标量(时间)
"name": "accessorAnimationInput"
}
]位置数据 (accessor)
{
"bufferView": 7,
"componentType": 5126, // FLOAT
"count": 36, // 36 个位置
"type": "VEC3", // 三维向量 (x, y, z)
"name": "accessorAnimationPositions"
}🔧 在 Three.js 中的使用
加载和播放动画
import { useGLTF, useAnimations } from '@react-three/drei';
function Player() {
const { scene, animations } = useGLTF('/models/Actor/actor.gltf');
const { actions, names } = useAnimations(animations, scene);
// animations 包含:
// [
// { name: "Standard_Walk", duration: 1.167, ... },
// { name: "Idle", duration: 8.333, ... },
// { name: "Standard_Run", duration: 0.733, ... }
// ]
// 播放走路动画
actions['Standard_Walk']?.play();
}每个动画控制 156 个通道
// 每个骨骼 × 3 个属性 = 通道数
53 个骨骼 × 3 (translation, rotation, scale) = 159 个通道📝 完整的动画绑定链路
1. 骨骼定义 (nodes)
├── Hips (索引 3)
├── Spine (索引 4)
└── ... (共 53 个骨骼)
2. 蒙皮绑定 (skins)
├── 顶点权重: vertex[0] → 80% Spine + 20% Hips
└── inverseBindMatrices: 初始姿态
3. 动画数据 (animations)
├── 时间轴: [0, 0.033, 0.066, ..., 1.167]
├── Hips.translation: [(0, 0.989, -0.001), ...]
└── Hips.rotation: [(-0.031, -0.046, -0.029, 0.998), ...]
4. 运行时更新
├── t = 0.5 秒 → 插值计算骨骼变换
├── 骨骼变换 → 影响顶点位置
└── 渲染新的模型姿态🎓 总结
glTF 通过这种分层设计,实现了高效的 模型 + 动画 存储和传输! 🚀