Difference between makeBasis and extractBasis in three.js - three.js

From three.js doc:
.makeBasis ( xAxis, zAxis, zAxis ) this
Creates the basis matrix consisting of the three provided axis vectors. Returns the current matrix.
# .extractBasis ( xAxis, zAxis, zAxis ) this
Extracts basis of into the three axis vectors provided. Returns the current matrix.
What's the difference between these two methods?
makeBasis looks a bit strange. Create a basis matrix and then return the current matrix? Doesn't make any sense.

The answer to your question should be clear by looking at the source code of Matrix4.js.
extractBasis: function ( xAxis, yAxis, zAxis ) {
var te = this.elements;
xAxis.set( te[ 0 ], te[ 1 ], te[ 2 ] );
yAxis.set( te[ 4 ], te[ 5 ], te[ 6 ] );
zAxis.set( te[ 8 ], te[ 9 ], te[ 10 ] );
return this;
},
makeBasis: function ( xAxis, yAxis, zAxis ) {
this.set(
xAxis.x, yAxis.x, zAxis.x, 0,
xAxis.y, yAxis.y, zAxis.y, 0,
xAxis.z, yAxis.z, zAxis.z, 0,
0, 0, 0, 1
);
return this;
},
three.js r.73

Related

ThreeJS - Transform by applyMatrix4 doesn't preserve eigen vector's direction

I transformed a vector which lays on the transformation matrix's eigen space using Object3D.applyMatrix4. I expected it not to move because the eigen value was 1, or at least stay on the eigen span, but it moved to an unexpected place.
I've made an sample project: stackblitz
But below is probably all the code you would need to examine
let pointGeo = new THREE.Geometry()
pointGeo.vertices = [new THREE.Vector3(1,-1,1)]
let pmat = new THREE.PointsMaterial({color: 0x00f0f0, size: 0.3})
let pointObj = new THREE.Points(pointGeo, pmat)
let matrix = new THREE.Matrix4()
matrix.set( 1, 3, 3, 0,
-3, -5, -3, 0,
3, 3, 1, 0,
0, 0, 0, 1)
pointObj.applyMatrix4(matrix)
Specifically I'm transforming a point (1, -1, 1) (where the purple square is) with a matrix. Multiplication by the matrix shouldn't change the value. (double checked by hand calculating) But it moves it to where the blue square is.
Is there other stages where some other transformation is applied? What am I missing here?
I've found that Object3D.applyMatrix4 wasn't the right function for explicitly defining local matrix. I tried setting Object3D.matrix property directly and it worked. I changed code like this:
o.matrix = mat
o.matrixAutoUpdate = false
o.updateMatrixWorld(true)
here is the source for applyMatrix4... are you hand applying your matrix exactly like this:
applyMatrix4 ( m ) {
var x = this.x, y = this.y, z = this.z;
var e = m.elements;
var w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;
this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;
this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;
return this;
},
```

What is the attribute for a uicontrol object equivalent to deprecated uititle method

I want to pretty much replicate the GUI implemented here:
and here is what I have got so far:
// first create the GUI panel
figw = 220;
figh = 160;
close(1)
f = figure(1, "position", [0 0 figw figh]);
//PUSH TO STOP
hstop = uicontrol(f, "style", "pushbutton", "Min", 0, "Max", 1, "string", " STOP",..
"position", [10 10 61 50], "callback", "infiniteloop=%F");
// TRIGGERED MODE
htrig = uicontrol(f, "style", "radiobutton", "Min", 0, "Max", 1, "string", "free/trig", "value", 0,..
"position", [80 10 20 20]);
//httrig=uititle(htrig,"free/trig","r")
// BINNING x2
hbin = uicontrol(f, "style", "radiobutton", "Min", 0, "Max", 1, "value", 0,..
"position", [80 40 20 20]);
//htbin=uititle(hbin,"bin x2","r")
// GREYSCALE
hbri = uicontrol("style", "slider", "Min", 1, "Max", 255, "value", 128,..
"position", [10 70 200 20]);
//htbri=uititle(hbri,"greyscale")
// EXPOSURE (only for untriggered)
hexp = uicontrol("style", "slider", "Min", 1, "Max", 1200, "value", 40,..
"position", [10 120 200 20]);
//htexp=uititle(hexp,"exposure time")
my main issue at this moment is that I can't find the equivalent attribute / property for the uicontrol objects which corresponds to the deprecated uititle method.
I could indeed use textboxes and find a workaround but that's not the ideal solution given all the positioning headaches. I was wondering if there is still such an attribute which accepts a stering and the put in the described position like r, t, l and b? Thanks for your help in advance.
The famous uititle from Enrico Segre (emeritus Scilab contributor) could reborn like this, thanks to new layout features of uicontrols:
function t=uititle(h,text)
pos = h.Position;
pos(4)=pos(4)*2;
f = uicontrol("style","frame","position",pos,"layout","grid")
lay_opt = createLayoutOptions("grid", [2,1])
set(f,"layout_options",lay_opt);
c = createConstraints("grid");
h.parent = f;
t=uicontrol(f,"style","text","string",text,"horizontalalignment","center",...
"constraints",c);
endfunction
clf
sl=uicontrol("style","slider","position",[10 10 200 20])
uititle(sl,"a slider")

Rotation after a Rotation not acting how I Expect

I have a rubiks-cube-like puzzle I am trying to model in webgl using Three.js:
Each of the two-color centers can rotate. When they rotate, they bring all of the pieces around them along on the rotation. For example, if we rotate the orange-blue center, this is what happens:
When you complete a rotation, everything lines up:
However, now when I try to rotate the Orange-White center, I get strange behavior for the two pieces it inherited from the Orange-Blue center after the first rotation:
I expect them to rotate like the other pieces, but instead they rotate differently.
I am using Three.js's Object3D.rotateOnAxis() function to do my rotations:
function rotate ( center, distance ) {
var axis = center.axis;
center.model.rotateOnAxis ( axis, distance );
for ( var i in center.stickers ) {
center.stickers[i].rotateOnAxis ( axis, distance );
}
for ( var i in center.children ) {
center.children[i].model.rotateOnAxis ( axis, distance );
//Note: the stickers are just the colored faces
for ( var s in center.children[i].stickers ) {
center.children[i].stickers[s].rotateOnAxis ( axis, distance );
}
}
}
Here is what my key-press code looks like:
function showCube() {
//set stuff up, then...
count = 0;
parent.onkeypress = function(event) {
if ( count < 6 ) {
rotate( blocks.centers [ "BO" ], Math.PI / 6 );
count++;
if ( count == 6 ) {
moveFace ( blocks, "O1", "OY", "BW" );
moveFace ( blocks, "O2", "OW", "BY" );
moveFace ( blocks, "B1", "BW", "OY" );
moveFace ( blocks, "B2", "BY", "OW" );
moveCorner ( blocks, "BOW", "OW", "OY" );
moveCorner ( blocks, "BOW", "BW", "BY" );
moveCorner ( blocks, "BOY", "OY", "OW" );
moveCorner ( blocks, "BOY", "BY", "BW" );
}
} else {
rotate( blocks.centers [ "OW" ], Math.PI / 6 );
}
}
}
function moveFace ( blocks, child, oldParent, newParent ) {
var index = blocks.centers [ oldParent ].children.indexOf ( blocks.faces [ child ] );
blocks.centers [ oldParent ].children.splice ( index, 1 );
blocks.centers [ newParent ].children.push ( blocks.faces [ child ] );
}
function moveCorner ( blocks, child, oldParent, newParent ) {
var index = blocks.centers [ oldParent ].children.indexOf ( blocks.corners [ child ] );
blocks.centers [ oldParent ].children.splice ( index, 1 );
blocks.centers [ newParent ].children.push ( blocks.corners [ child ] );
}
Interestingly, to get the Blue-Orange-Yellow corner to rotate correctly, I need to do the rotation around the difference between the BO vector and the OW vector.
That is to say:
Blue-Orange axis is the normalized vector of: (0, 1, 1)
Orange-White axis is the normalized vector of: (1, 0, 1)
After the first rotation is complete, if I try to rotate the BOY
corner around the normal of (1, 0, 1), I get the behavior shown in
the pictures.
However, if I try to rotate it around (0, 1, 1) - (1,
0, 1), i.e. (-1, 1, 0), I get the desired behavior.
I don't understand what's happening. Can you help me update my rotate function so I get the behavior I want, without having to keep a long list of past rotations that a piece has experienced?
I suspect that after I do my first rotation, I need to tell the piece to "zero" its rotation state without causing any motion, but I'm not quite sure how to do that, or if it's the right approach.
You can play with the thing here: http://joshuad.net/clover-cube/so-question/
Thanks!
I fixed it by changing my rotate method to this:
function rotate ( center, distance ) {
var axis = center.axis;
center.model.rotateOnAxis ( axis, distance );
applyStatesToMatrixDirectly ( center.model );
for ( var stickerIndex in center.stickers ) {
center.stickers[stickerIndex].rotateOnAxis ( axis, distance );
applyStatesToMatrixDirectly ( center.stickers[stickerIndex] );
}
for ( var childIndex in center.children ) {
center.children[childIndex].model.rotateOnAxis ( axis, distance );
applyStatesToMatrixDirectly ( center.children[childIndex].model );
for ( var childStickerIndex in center.children[childIndex].stickers ) {
center.children[childIndex].stickers[childStickerIndex].rotateOnAxis ( axis, distance );
applyStatesToMatrixDirectly ( center.children[childIndex].stickers[childStickerIndex] );
}
}
}
function applyStatesToMatrixDirectly ( model ) {
model.updateMatrix();
model.geometry.applyMatrix( model.matrix );
model.position.set( 0, 0, 0 );
model.rotation.set( 0, 0, 0 );
model.scale.set( 1, 1, 1 )
model.updateMatrix();
}
The idea is that the function applyStatesToMatrixDirectly() applies the rotation directly to the model matrix and then reset all of the rotation data (as well as everything else). This allows the model to "forget" that it has been rotated, allowing the new rotateOnAxis to work.

Tileable (repeating) regions of textures?

Is it possible to specify rectangular regions of a texture that should repeat across single triangles/quads?
If not, I think I know how I'd write the shader from scratch. But is it possible to add the uniforms, attributes and GLSL code bits to any of the existing three.js materials? (i.e., so I can still use phong, lambert, etc. and apply my edits.)
You want to repeat a sub-region of a texture, but three.js allows for repeating the entire texture.
There is a work-around, however. You will need to tessellate your geometry, and modify its UVs.
Here is how you can do that with PlaneGeometry.
// geometry
var geometry = new THREE.PlaneGeometry( 10, 10, 4, 4 ); // set the pattern repeat here: it is 4
// reset the uvs to be 0 or 1 for each face
var uvs = geometry.faceVertexUvs[ 0 ];
for( i = 0; i < uvs.length; i += 2 ) {
uvs[ i ][ 0 ].set( 0, 1 ); // first triangle
uvs[ i ][ 1 ].set( 0, 0 );
uvs[ i ][ 2 ].set( 1, 1 );
uvs[ i + 1 ][ 0 ].set( 0, 0 ); // second triangle
uvs[ i + 1 ][ 1 ].set( 1, 0 );
uvs[ i + 1 ][ 2 ].set( 1, 1 );
}
// texture
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.offset.set( 0.5, 0.25 ); // set the sub-texture offset here
texture.repeat.set( 0.25, 0.25 ); // set the sub-texture scale here
If you do not like that solution, you can extend one of the three.js built-in materials using the approach described in this SO post.
three.js r.69

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]}
]},
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.
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

Resources