buildSkin method
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;
}