jointChainGlb function
A thin bar skinned to a chain of joints joints, each 0.1 m above the
last, with a wave animation turning every joint a little about +Z and
back over 1 s — for timing many joints.
Implementation
Uint8List jointChainGlb(int joints) {
final w = GlbWriter();
final positions = <double>[],
normals = <double>[],
js = <int>[],
ws = <double>[];
final indices = <int>[];
for (var j = 0; j <= joints; j++) {
final y = j * 0.1;
for (final (cx, cz) in const [
(-1.0, -1.0),
(1.0, -1.0),
(1.0, 1.0),
(-1.0, 1.0),
]) {
positions.addAll([cx * 0.05, y, cz * 0.05]);
normals.addAll([cx * 0.7071, 0, cz * 0.7071]);
js.addAll([math.min(j, joints - 1), 0, 0, 0]);
ws.addAll([1, 0, 0, 0]);
}
}
for (var l = 0; l < joints; l++) {
for (var c = 0; c < 4; c++) {
final a = l * 4 + c, b = l * 4 + (c + 1) % 4;
indices.addAll([a, b + 4, b, a, a + 4, b + 4]);
}
}
final mesh = w.addMesh([
{
'attributes': {
'POSITION': w.addFloats(positions, 'VEC3', withBounds: true),
'NORMAL': w.addFloats(normals, 'VEC3'),
'JOINTS_0': w.addInts(js, 'VEC4', 5123),
'WEIGHTS_0': w.addFloats(ws, 'VEC4'),
},
'indices': w.addInts(indices, 'SCALAR', 5123, indices: true),
},
], name: 'Chain');
// Joints are added child first so each can name its child.
final nodes = List<int>.filled(joints, 0);
for (var j = joints - 1; j >= 0; j--) {
nodes[j] = w.addNode({
'name': 'joint $j',
'translation': [0, j == 0 ? 0 : 0.1, 0],
if (j < joints - 1) 'children': [nodes[j + 1]],
});
}
final ibm = <double>[];
for (var j = 0; j < joints; j++) {
ibm.addAll([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, -0.1 * j, 0, 1]);
}
w.addSkin({'joints': nodes, 'inverseBindMatrices': w.addFloats(ibm, 'MAT4')});
final body = w.addNode({'name': 'Chain', 'mesh': mesh, 'skin': 0});
w.setScene([body, nodes[0]]);
final s = math.sin(0.05), c = math.cos(0.05);
final times = w.addFloats([0, 0.5, 1], 'SCALAR');
final turn = w.addFloats([0, 0, 0, 1, 0, 0, s, c, 0, 0, 0, 1], 'VEC4');
w.addAnimation({
'name': 'wave',
'samplers': [
{'input': times, 'output': turn, 'interpolation': 'LINEAR'},
],
'channels': [
for (final node in nodes)
{
'sampler': 0,
'target': {'node': node, 'path': 'rotation'},
},
],
});
return w.toGlb();
}