I use OpenCV to process any given image (segment, convex hull, cavity). Then I use Three.js to use these coordinates as bones. To create a SkinnedMesh, I started with this cylinder example, which is 1-linear. Since my goal is to support arms/legs, I decided to get distance from vertex to closest bone, which resulted in many failures.
The vertices at the skinIndex don’t respond. The shadow moves with the animation, but not the model. The sides move, but not the front/back. This seems like a timing issue, which may require a promise/async(?) I have tried calling needsUpdate, assigning a count, setting dynamic to true, etc.
I realize this is unfinished homework, but is something fundamentally wrong?
https://codepen.io/kpachinger/pen/ZVgejg
var skinIndices = [];
var skinWeights = [];
function distance(x1, y1, x2, y2) {
let a = x1 - x2;
let b = y1 - y2;
let c = 1 - Math.sqrt(a * a + b * b);
c = Math.abs(c);
return c;
}
let pos = geometry.attributes.position;
var promise = new Promise(function(resolve, reject) {
let root = sto.skind[0].id;
let skin = [];
for (let i = 0; i < pos.count; i++) {
x1 = pos.array[i * 2];
y1 = pos.array[i * 3];
skin[i] = [];
for (let j = 0; j < bones.length; j++) {
x2 = bones[j].positionGlobal.x / sto.width;
y2 = bones[j].positionGlobal.y / sto.height;
if (bones[j].name != 'Root' && bones[j].name != 'Bone_0') {
skin[i].push(distance(x1, y1, x2, y2) + '|' + bones[j].id);
}
}
skin[i].sort();
let closest = skin[i][0];
closest = closest.split('|');
closest = {
'dist': closest[0],
'id': closest[1] * 1
};
const halfHeight = area / (sto.width + sto.height) / 4;
const segmentHeight = halfHeight / 3;
const y = Math.abs(y1);
var skinIndexY = Math.floor(y / segmentHeight / 2);
var skinWeightY = ((y / segmentHeight) * (halfHeight / 2)) / 2;
skinIndices.push(
skinIndexY,
closest.id,
closest.id,
root);
//all add up to 1
skinWeights.push(
0.5 - (skinWeightY*0.50),
(skinWeightY*0.50),
0.25,
0.25);
}
resolve('Vertices => SkinnedMesh');
});
promise.then(function(value) {
console.log(value);
geometry.addAttribute('skinIndex', new THREE.Uint16BufferAttribute(skinIndices, 4));
geometry.addAttribute('skinWeight', new THREE.Float32BufferAttribute(skinWeights, 4));
mesh = new THREE.SkinnedMesh(geometry, [material, materialSides]);
let skeleton = new THREE.Skeleton(bones);
mesh.add(bones[0]);
mesh.bind(skeleton);
let skeletonHelper = new THREE.SkeletonHelper(mesh);
skeletonHelper.material.linewidth = 2;
group.add(mesh, skeletonHelper);
return mesh;
});