jointChainGlb function

Uint8List jointChainGlb(
  1. int joints
)

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();
}