diff --git a/src/library/VRMExporterv0.js b/src/library/VRMExporterv0.js index fec08cac..1cbf562a 100644 --- a/src/library/VRMExporterv0.js +++ b/src/library/VRMExporterv0.js @@ -97,7 +97,7 @@ function getVRM0BoneName(name){ return name; } export default class VRMExporterv0 { - parse(vrm, avatar, onDone) { + parse(vrm, avatar, rootSpringBones, colliderBones, onDone) { const vrmMeta = convertMetaToVRM0(vrm.meta); const humanoid = convertHumanoidToVRM0(vrm.humanoid); @@ -417,7 +417,48 @@ export default class VRMExporterv0 { //const outputVrmMeta = ToOutputVRMMeta(vrmMeta, icon, outputImages); const outputVrmMeta = vrmMeta; - //const outputSecondaryAnimation = toOutputSecondaryAnimation(springBone, nodeNames); + + const rootSpringBonesIndexes = []; + rootSpringBones.forEach(rootSpringBone => { + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (node.name === rootSpringBone.name) { + rootSpringBonesIndexes.push(i); + break; + } + } + }) + + const colliderGroups = []; + const colliderGroupsIndexes = []; + colliderBones.forEach((colliderBone, i) => { + const nodeIndex = nodes.indexOf(colliderBone); + const colliderGroup = { + "colliders": [ + { "offset": { "x": 0, "y": 0.05, "z": 0 }, "radius": 0.075 } + ], + "node": nodeIndex + } + colliderGroups.push(colliderGroup); + colliderGroupsIndexes.push(i); + }) + + const outputSecondaryAnimation = { + "boneGroups": [ + { + "bones": rootSpringBonesIndexes, + "center": -1, + "colliderGroups": colliderGroupsIndexes, + "dragForce": 0.452, + "gravityDir": { "x": 0, "y": 0, "z": 0 }, + "gravityPower": 0, + "hitRadius": 0.01, + "stiffiness": 1 + } + ], + "colliderGroups": colliderGroups, + }; + const bufferViews = []; bufferViews.push(...images.map((image) => ({ buffer: imageBitmap2png(image.imageBitmap), @@ -479,7 +520,7 @@ export default class VRMExporterv0 { materialProperties, humanoid: vrmHumanoid, meta: outputVrmMeta, - //secondaryAnimation: outputSecondaryAnimation, + secondaryAnimation: outputSecondaryAnimation, specVersion: "0.0" }, }, diff --git a/src/library/download-utils.js b/src/library/download-utils.js index 07e35401..c2126055 100644 --- a/src/library/download-utils.js +++ b/src/library/download-utils.js @@ -157,24 +157,53 @@ function parseVRM (glbModel, avatar, isVrm0 = false){ ...getVRMBaseData(avatar), ...getAvatarData(glbModel, "CharacterCreator"), } + let skinnedMesh; glbModel.traverse(child => { if (child.isSkinnedMesh) skinnedMesh = child; }) - skinnedMesh.skeleton.bones.forEach(bone => { - if (bone.name !== 'root') { - bone.position.x *= -1; - bone.position.z *= -1; - } - }) - skinnedMesh.skeleton.bones.forEach(bone => { - bone.updateMatrix(); - bone.updateMatrixWorld(); - }) - skinnedMesh.skeleton.calculateInverses(); - skinnedMesh.skeleton.computeBoneTexture(); - skinnedMesh.skeleton.update(); - exporter.parse(vrmData, glbModel, (vrm) => { + + const reverseBonesXZ = () => { + skinnedMesh.skeleton.bones.forEach(bone => { + if (bone.name !== 'root') { + bone.position.x *= -1; + bone.position.z *= -1; + } + }) + skinnedMesh.skeleton.bones.forEach(bone => { + bone.updateMatrix(); + bone.updateMatrixWorld(); + }) + skinnedMesh.skeleton.calculateInverses(); + skinnedMesh.skeleton.computeBoneTexture(); + skinnedMesh.skeleton.update(); + } + reverseBonesXZ(); + + const headBone = skinnedMesh.skeleton.bones.filter(bone => bone.name === 'head')[0]; + + const rootSpringBones = []; + const processSpringBones = () => { + headBone.children.forEach(hairTypeGroup => { + if (!hairTypeGroup.name.startsWith('hair_')) return; + const nameParts = hairTypeGroup.name.split('_'); + const hairId = nameParts[1]; + if (hairId === avatar.head.traitInfo.id) { // note: only export the hairTypeGroup of current selected hair. + hairTypeGroup.children.forEach(strandRoot => { + rootSpringBones.push(strandRoot); + }); + } + }); + } + processSpringBones(); + + const colliderBones = []; + const processColliderBones = () => { + colliderBones.push(headBone); + } + processColliderBones(); + + exporter.parse(vrmData, glbModel, rootSpringBones, colliderBones, (vrm) => { resolve(vrm) }) })