Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the meaning of skin indices and skin weights?

This is undocumented, so I'm asking here. I'm trying to animate a mesh in JavaScript. I'm using Blender->Three.js exporter because it is convenient. I can't use Three.js itself because I was not able to figure out how to solve certain problems on it (rendering the normals and depth informations of a scene with animated meshes to a buffer). So, how do you read the "skinIndices" and "skinWeights" properties that get exported from Blender to Three.js? What do they mean, and what are they roles when calculating the position of the vertices on the animations?

"bones" : [
    {"parent":-1,"name":"pelvis","pos":[-3.52132e-08,0.0410043,0.880063],"rotq":[0,0,0,1]},
    {"parent":0,"name":"thigh.L","pos":[0.0878887,0.00522349,0.102822],"rotq":[0,0,0,1]},
    {"parent":1,"name":"shin.L","pos":[0.103679,0.00638392,-0.445744],"rotq":[0,0,0,1]},
    {"parent":2,"name":"foot.L","pos":[0.0655578,0.0194668,-0.418675],"rotq":[0,0,0,1]},
    {"parent":3,"name":"toe.L","pos":[0.0280578,-0.107185,-0.0704246],"rotq":[0,0,0,1]},
    {"parent":3,"name":"heel.L","pos":[3.58224e-05,0.036576,-0.0885088],"rotq":[0,0,0,1]},
    {"parent":0,"name":"thigh.R","pos":[-0.0878888,0.00522352,0.102822],"rotq":[0,0,0,1]},
    {"parent":6,"name":"shin.R","pos":[-0.103679,0.00638412,-0.445745],"rotq":[0,0,0,1]},
    {"parent":7,"name":"foot.R","pos":[-0.0655576,0.0194677,-0.418675],"rotq":[0,0,0,1]},
    {"parent":8,"name":"toe.R","pos":[-0.0280577,-0.107185,-0.0704248],"rotq":[0,0,0,1]},
    {"parent":8,"name":"heel.R","pos":[-3.57926e-05,0.036576,-0.0885083],"rotq":[0,0,0,1]},
    {"parent":0,"name":"stomach","pos":[5.37268e-09,-0.008465,0.121596],"rotq":[0,0,0,1]},
    {"parent":11,"name":"chest","pos":[1.94616e-08,0.0538289,0.269019],"rotq":[0,0,0,1]},
    {"parent":12,"name":"upper_arm.L","pos":[0.160045,-0.010388,0.159844],"rotq":[0,0,0,1]},
    {"parent":13,"name":"forearm.L","pos":[0.165089,0.0102809,-0.232678],"rotq":[0,0,0,1]},
    {"parent":14,"name":"hand.L","pos":[0.0980782,-0.0148839,-0.245313],"rotq":[0,0,0,1]},
    {"parent":15,"name":"index.L.001","pos":[0.019191,-0.040475,-0.0743723],"rotq":[0,0,0,1]},
    {"parent":16,"name":"index.L.002","pos":[-0.00562334,-0.00824448,-0.0310695],"rotq":[0,0,0,1]},
    {"parent":17,"name":"index.L.003","pos":[-0.00953785,-0.00126594,-0.0192741],"rotq":[0,0,0,1]},
    {"parent":15,"name":"middle.L.001","pos":[0.0191911,-0.0188201,-0.0769786],"rotq":[0,0,0,1]},
    {"parent":19,"name":"middle.L.002","pos":[0.00288424,-0.00695575,-0.0326532],"rotq":[0,0,0,1]},
    {"parent":20,"name":"middle.L.003","pos":[-0.0111618,-0.00550338,-0.0242877],"rotq":[0,0,0,1]},
    {"parent":15,"name":"ring.L.001","pos":[0.0186397,0.00194495,-0.0777299],"rotq":[0,0,0,1]},
    {"parent":22,"name":"ring.L.002","pos":[0.00393239,-0.00062982,-0.0309386],"rotq":[0,0,0,1]},
    {"parent":23,"name":"ring.L.003","pos":[-0.00873661,-0.00165674,-0.024165],"rotq":[0,0,0,1]},
    {"parent":15,"name":"pinky.L.001","pos":[0.0191911,0.02271,-0.0758559],"rotq":[0,0,0,1]},
    {"parent":25,"name":"pinky.L.002","pos":[-0.0057596,0.0014303,-0.0236881],"rotq":[0,0,0,1]},
    {"parent":26,"name":"pinky.L.003","pos":[-0.00877053,-0.0020119,-0.0195478],"rotq":[0,0,0,1]},
    {"parent":15,"name":"thumb.L.001","pos":[-0.0073517,-0.0318671,-0.0156776],"rotq":[0,0,0,1]},
    {"parent":28,"name":"thumb.L.002","pos":[-0.00941652,-0.0166059,-0.0179188],"rotq":[0,0,0,1]},
    {"parent":29,"name":"thumb.L.003","pos":[-0.0081799,-0.0129757,-0.0276645],"rotq":[0,0,0,1]},
    {"parent":12,"name":"upper_arm.R","pos":[-0.160044,-0.010388,0.159844],"rotq":[0,0,0,1]},
    {"parent":31,"name":"forearm.R","pos":[-0.165089,0.0102809,-0.232679],"rotq":[0,0,0,1]},
    {"parent":32,"name":"hand.R","pos":[-0.0980774,-0.0148839,-0.245313],"rotq":[0,0,0,1]},
    {"parent":33,"name":"index.R.001","pos":[-0.0185038,-0.0404748,-0.0743726],"rotq":[0,0,0,1]},
    {"parent":34,"name":"index.R.002","pos":[0.00562337,-0.00824449,-0.0310695],"rotq":[0,0,0,1]},
    {"parent":35,"name":"index.R.003","pos":[0.00953785,-0.00126596,-0.0192741],"rotq":[0,0,0,1]},
    {"parent":33,"name":"middle.R.001","pos":[-0.0185038,-0.0188199,-0.0769789],"rotq":[0,0,0,1]},
    {"parent":37,"name":"middle.R.002","pos":[-0.00288421,-0.00695577,-0.0326532],"rotq":[0,0,0,1]},
    {"parent":38,"name":"middle.R.003","pos":[0.0111619,-0.00550339,-0.0242877],"rotq":[0,0,0,1]},
    {"parent":33,"name":"ring.R.001","pos":[-0.0179525,0.00194514,-0.0777302],"rotq":[0,0,0,1]},
    {"parent":40,"name":"ring.R.002","pos":[-0.00393245,-0.000629827,-0.0309386],"rotq":[0,0,0,1]},
    {"parent":41,"name":"ring.R.003","pos":[0.00873658,-0.00165676,-0.024165],"rotq":[0,0,0,1]},
    {"parent":33,"name":"pinky.R.001","pos":[-0.0185039,0.0227101,-0.0758562],"rotq":[0,0,0,1]},
    {"parent":43,"name":"pinky.R.002","pos":[0.0057596,0.00143027,-0.0236881],"rotq":[0,0,0,1]},
    {"parent":44,"name":"pinky.R.003","pos":[0.00877053,-0.00201192,-0.0195478],"rotq":[0,0,0,1]},
    {"parent":33,"name":"thumb.R.001","pos":[0.00803882,-0.0318669,-0.0156779],"rotq":[0,0,0,1]},
    {"parent":46,"name":"thumb.R.002","pos":[0.00941664,-0.0166059,-0.0179188],"rotq":[0,0,0,1]},
    {"parent":47,"name":"thumb.R.003","pos":[0.00817987,-0.0129757,-0.0276645],"rotq":[0,0,0,1]},
    {"parent":12,"name":"neck","pos":[1.6885e-08,-0.0164749,0.225555],"rotq":[0,0,0,1]},
    {"parent":49,"name":"head","pos":[0.000806741,-0.0273245,0.0637051],"rotq":[0,0,0,1]}],

"skinIndices" : [
        11,0,11,0,1,11,11,0,0,11,0,11,1,11,1,11,0,11,11,0,11,0,11,0,1,11,11,0,11,0,0,11,1,11,1,11,0,11,0,11,0,11,12,0,0,11,0,11,
        0,11,12,0,12,0,11,0,11,0,11,0,12,0,11,0,11,0,11,0,12,0,12,11,11,0,11,0,12,13,11,0,0,11,11,0,12,13,12,13,0,11,12,13,12,0,
        12,0,13,12,13,12,12,13,12,0,12,13,13,12,12,13,12,13,13,12,13,0,12,13,12,0,12,13,13,0,12,0,13,0,0,13,13,0,13,0,0,13,0,13,
        13,0,13,0,0,13,13,12,13,12,13,12,13,0,13,0,13,0,13,12,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,0,13,
        (... too big)]

"skinWeights" : [
    0.454566,0.443267,0.456435,0.4405,0.568642,0.331477,0.452697,0.446034,0.600277,0.577654,0.603738,0.578153,0.557686,0.334716,
    0.579597,0.328238,0.596817,0.577156,0.481496,0.447683,0.604872,0.59171,0.466162,0.448242,0.567426,0.35812,0.49683,0.447124,
    0.618979,0.590887,0.592533,0.590764,0.578989,0.341559,0.555862,0.37468,0.477411,0.438341,0.617349,0.569542,0.454728,0.432345,
    0.401061,0.337472,0.500093,0.444338,0.633534,0.572105,0.601164,0.56698,0.388198,0.308292,0.413925,0.366652,0.449179,0.424051,
    0.618298,0.58735,0.458406,0.430254,0.473939,0,0.439952,0.417849,0.605333,0.579977,0.631263,0.594722,0.517687,0,0.430191,0.274572,
    (... too big)]


"animations" : [
    {"name":"ArmatureAction",
    "fps":24,
    "length":0.625,
    "hierarchy":
    [{"parent":-1,"keys":[
        {"time":0,"pos":[-3.52132e-08,0.0410043,0.880063],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[-3.52132e-08,0.0410043,0.880063]},
        {"time":0.625,"pos":[-3.52132e-08,0.0410043,0.880063],"rot":[0,0,0,1],"scl":[1,1,1]}]
    },
    {"parent":0,"keys":[
        {"time":0,"pos":[0.0878887,0.00522349,0.102822],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[0.0878887,0.00522349,0.102822],"rot":[-0.36166,-1.53668e-08,-7.05768e-10,0.93231]},
        {"time":0.625,"pos":[0.0878887,0.00522349,0.102822],"rot":[0,0,0,1],"scl":[1,1,1]}
    ]},
    {"parent":1,"keys":[
        {"time":0,"pos":[0.103679,0.00638392,-0.445744],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[0.103679,0.00638392,-0.445744]},
        {"time":0.625,"pos":[0.103679,0.00638392,-0.445744],"rot":[0,0,0,1],"scl":[1,1,1]}
    ]},
    {"parent":2,"keys":[
        {"time":0,"pos":[0.0655578,0.0194668,-0.418675],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[0.0655578,0.0194668,-0.418675]},
        {"time":0.625,"pos":[0.0655578,0.0194668,-0.418675],"rot":[0,0,0,1],"scl":[1,1,1]}
    ]},
    {"parent":3,"keys":[
        {"time":0,"pos":[0.0280578,-0.107185,-0.0704246],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[0.0280578,-0.107185,-0.0704246]},
        {"time":0.625,"pos":[0.0280578,-0.107185,-0.0704246],"rot":[0,0,0,1],"scl":[1,1,1]}
    ]},
    {"parent":4,"keys":[
        {"time":0,"pos":[3.58149e-05,0.036576,-0.0885088],"rot":[0,0,0,1],"scl":[1,1,1]},
        {"time":0.291667,"pos":[3.58149e-05,0.036576,-0.0885088]},
        {"time":0.625,"pos":[3.58149e-05,0.036576,-0.0885088],"rot":[0,0,0,1],"scl":[1,1,1]}
    ]},
like image 812
MaiaVictor Avatar asked Jan 11 '23 19:01

MaiaVictor


2 Answers

Each vertex corresponds to one skin index which corresponds to one skin weight. The skin index is the index of the bone that the particular vertex is influenced by (each vertex can only belong to one bone). The skin weight is the amount of influence that bone has over that vertex.

like image 53
03civic Avatar answered Mar 16 '23 13:03

03civic


The skinIndices and skinWeights properties are arrays of arrays (technically the inner arrays are three.js Vector4 objects). Each item in the outer array of either corresponds, one-to-one, based on the indexed position, with each vertex in the mesh.

Here's the relevant JSONLoader code that creates the values for these properties from a three.js JSON model file:

if ( json.skinWeights ) {

    for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {

        var x = json.skinWeights[ i ];
        var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
        var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
        var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;

        geometry.skinWeights.push( new Vector4( x, y, z, w ) );

    }

}

if ( json.skinIndices ) {

    for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {

        var a = json.skinIndices[ i ];
        var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
        var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
        var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;

        geometry.skinIndices.push( new Vector4( a, b, c, d ) );

    }
}

The docs for the three.js Geometry object were updated to include info about this [some formatting and two inconsistency corrections mine]:

Just like the skinWeights property, the skinIndices' values correspond to the geometry's vertices. Each vertex can have up to 4 bones associated with it. So if you look at the first vertex, and the first skin index, this will tell you the bones associated with that vertex. For example the first vertex could have a value of ( 10.05, 30.10, 12.12 ). Then the first skin index could have the value of ( 10, 2, 0, 0 ). The first skin weight could have the value of ( 0.8, 0.2, 0, 0 ). In affect this would take the first vertex, and then the bone mesh.bones[10] and apply it 80% of the way. Then it would take the bone mesh.bones[2] and apply it 20% of the way. The next two values have a weight of 0, so they would have no affect.

In code another example could look like this:

// e.g.
geometry.skinIndices[15] = new THREE.Vector4(   0,   5,   9, 0 );
geometry.skinWeights[15] = new THREE.Vector4( 0.2, 0.5, 0.3, 0 );

// corresponds with the following vertex
geometry.vertices[15];

// these bones will be used like so:
skeleton.bones[0]; // weight of 0.2
skeleton.bones[5]; // weight of 0.5
skeleton.bones[9]; // weight of 0.3
skeleton.bones[10]; // weight of 0
like image 40
Kenny Evitt Avatar answered Mar 16 '23 12:03

Kenny Evitt