骨骼动画是目前最常用的模型动画,
这一节将增加对骨骼动画的支持,
使用javascript进行基于cpu的骨骼更新,
使用vertex shader进行基于gpu的顶点蒙皮。
所用模型和动画数据都导出自Unity3D。
动画数据加载
读取了骨架、动画clip(包含动画曲线关键帧)、模型的bindpose、顶点的骨骼索引和权重:
function on_mesh_data_load(data, mesh) {
var offset = [0];
read_string(data, offset);
var bone_count = DataLoader.ReadInt32(data, offset);
var bone_array = [];
var bone_map = {};
for(var i=0; i<bone_count; i++) {
var b_name = read_string(data, offset);
var b_pos = read_vector3(data, offset);
var b_rot = read_quaternion(data, offset);
var b_sca = read_vector3(data, offset);
var parent = DataLoader.ReadInt32(data, offset);
var b = {
name:b_name,
pos_loc:b_pos,
rot_loc:new Quaternion().set(b_rot),
sca_loc:b_sca,
children:{}
};
if(parent >= 0) {
b['parent'] = bone_array[parent];
b['parent']['children'][b_name] = b;
} else {
b['parent'] = null;
}
bone_array[i] = b;
bone_map[b_name] = b;
}
mesh.bone_array = bone_array;
mesh.bone_map = bone_map;
var clip_count = DataLoader.ReadInt32(data, offset);
var clips = {};
for(var i=0; i<clip_count; i++) {
var c_name = read_string(data, offset);
c_name = c_name.substr(0, c_name.indexOf('_'));
var fps = DataLoader.ReadFloat32(data, offset);
var len = DataLoader.ReadFloat32(data, offset);
var mode = DataLoader.ReadUint8(data, offset);
var curve_count = DataLoader.ReadInt32(data, offset);
var curves = [];
for(var j=0; j<curve_count; j++) {
var path = read_string(data, offset);
var property = read_string(data, offset);
var key_count = DataLoader.ReadInt32(data, offset);
var keys = [];
for(var k=0; k<key_count; k++) {
var tan_in = DataLoader.ReadFloat32(data, offset);
var tan_out = DataLoader.ReadFloat32(data, offset);
var tan_mode = DataLoader.ReadInt32(data, offset);
var time = DataLoader.ReadFloat32(data, offset);
var value = DataLoader.ReadFloat32(data, offset);
keys[k] = {
tan_in:tan_in,
tan_out:tan_out,
tan_mode:tan_mode,
time:time,
value:value
};
}
curves[j] = {
path:path,
property:property,
keys:keys
};
}
clips[c_name] = {
name:c_name,
fps:fps,
len:len,
mode:mode,
curves:curves
};
}
mesh.clips = clips;
var renderer_count = DataLoader.ReadInt32(data, offset);
for(var i=0; i<renderer_count; i++) {
var r_name = read_string(data, offset);
var r_pos = read_vector3(data, offset);
var r_rot = read_quaternion(data, offset);
var r_sca = read_vector3(data, offset);
var r_bone_count = DataLoader.ReadInt32(data, offset);
var r_bones = [];
for(var i=0; i<r_bone_count; i++) {
var index = DataLoader.ReadInt32(data, offset);
if(index >=