buildSkin method

Map<String, dynamic> buildSkin(
  1. Map<String, dynamic> data
)

Implementation

Map<String, dynamic> buildSkin(Map<String, dynamic> data ) {
  int descending( a, b ) {
    return (b['weight'] - a['weight']).toInt();
  }

  const BONE_LIMIT = 4;

  final Map<String,dynamic> build = {
    'joints': [], // this must be an array to preserve the joint order
    'indices': {
      'array': <int>[],
      'stride': BONE_LIMIT
    },
    'weights': {
      'array': <double>[],
      'stride': BONE_LIMIT
    }
  };

  final sources = data['sources'];
  final Map<String, dynamic> vertexWeights = data['vertexWeights'];
  final vcount = vertexWeights['vcount'];
  final v = vertexWeights['v'];
  final jointOffset = vertexWeights['inputs']['JOINT']['offset'];
  final weightOffset = vertexWeights['inputs']['WEIGHT']['offset'];

  final jointSource = data['sources'][ data['joints']['inputs']['JOINT'] ];
  final inverseSource = data['sources'][ data['joints']['inputs']['INV_BIND_MATRIX'] ];

  final weights = sources[ vertexWeights['inputs']['WEIGHT']['id'] ]['array'];
  int stride = 0;

  // process skin data for each vertex

  for (int i = 0, l = vcount.length; i < l; i ++ ) {
    final jointCount = vcount[ i ]; // this is the amount of joints that affect a single vertex
    final vertexSkinData = [];

    for (int j = 0; j < jointCount; j ++ ) {
      final int skinIndex = v[ stride + jointOffset ];
      final weightId = v[ stride + weightOffset ];
      final skinWeight = weights[ weightId ];

      vertexSkinData.add({'index': skinIndex, 'weight': skinWeight});

      stride += 2;
    }

    // we sort the joints in descending order based on the weights.
    // this ensures, we only procced the most important joints of the vertex

    vertexSkinData.sort( descending );

    conv(List list, int index) {
      if(index < 0){
        return list[list.length-index];
      }
      if(index >= list.length){
        if((index-list.length) >= list.length){
          final o = (index/list.length).floor();
          return list[index-o];
        }
        return list[index-list.length];
      }
      return list[index];
    }
    // now we provide for each vertex a set of four index and weight values.
    // the order of the skin data matches the order of vertices
    for (int j = 0; j < BONE_LIMIT; j ++ ) {
      //final d = vertexSkinData.length > j ? vertexSkinData[ j ]:null;
      final d = conv(vertexSkinData,j);
      if ( d != null ) {
        build['indices']['array'].add( d['index']);
        build['weights']['array'].add( d['weight']);
      }
      else {
        build['indices']['array'].add( 0 );
        build['weights']['array'].add( 0.0 );
      }
    }
  }

  // setup bind matrix

  if ( data['bindShapeMatrix'] != null) {
    build['bindMatrix'] = Matrix4().copyFromArray( data['bindShapeMatrix'] ).transpose();
  }
  else {
    build['bindMatrix'] = Matrix4.identity();
  }

  // process bones and inverse bind matrix data

  for (int i = 0, l = jointSource['array'].length; i < l; i ++ ) {
    final name = jointSource['array'][ i ];
    final boneInverse = Matrix4().copyFromArray( inverseSource['array'], (i * inverseSource['stride']).toInt() ).transpose();
    build['joints'].add( { 'name': name, 'boneInverse': boneInverse } );
  }

  return build;
}