From 47f25a9d9bc5e83666cffb3613d8af5ddee9596b Mon Sep 17 00:00:00 2001 From: 0b5vr <0b5vr@0b5vr.com> Date: Wed, 14 Feb 2024 16:51:12 +0900 Subject: [PATCH] fix: Improve chest detection algorithm This fixes the issue that chest cannot be detected when intermediate chest bones has three or more children such as skirt spring bones --- src/lib/bvh-converter/mapSkeletonToVRM.ts | 34 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/lib/bvh-converter/mapSkeletonToVRM.ts b/src/lib/bvh-converter/mapSkeletonToVRM.ts index 2fc416a..64e6374 100644 --- a/src/lib/bvh-converter/mapSkeletonToVRM.ts +++ b/src/lib/bvh-converter/mapSkeletonToVRM.ts @@ -27,6 +27,27 @@ function objectBFS( return null; } +/** + * Traverse descendants of given object. + * It will return an array of object that the given evaluation function returns `true`. + * + * It will perform breadth first search. + */ +function objectTraverseFilter( + root: THREE.Object3D, + fn: (obj: THREE.Object3D) => boolean | void +): THREE.Object3D[] { + const result: THREE.Object3D[] = []; + + root.traverse((obj) => { + if (fn(obj)) { + result.push(obj); + } + }); + + return result; +} + /** * Traverse ancestors of given object. * Once the given function returns `true`, it stops the traversal operation and returns the object. @@ -346,10 +367,17 @@ export function mapSkeletonToVRM(root: THREE.Bone): Map { + // find chest candidate - descendants of the hips which has three or more children + const chestCands = objectTraverseFilter(hips, (obj) => { return obj !== hips && obj.children.length >= 3; - }) as THREE.Bone; + }) as THREE.Bone[]; + const chestCand = pickByProbability( + chestCands, + [ + { func: (obj) => evaluatorName(obj, 'upperchest'), weight: 1.0 }, + { func: (obj) => evaluatorName(obj, 'chest'), weight: 1.0 }, + ] + ); if (chestCand == null) { throw new Error('Cannot find chest.'); }