import * as THREE from 'three' ; import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader' ; import { GLTFNode , VRMSchema } from '../types' ; import { VRMSpringBone } from './VRMSpringBone' ; import { VRMSpringBoneColliderGroup , VRMSpringBoneColliderMesh } from './VRMSpringBoneColliderGroup' ; import { VRMSpringBoneGroup , VRMSpringBoneManager } from './VRMSpringBoneManager' ; import { VRMSpringBoneParameters } from './VRMSpringBoneParameters' ; const _v3A = new THREE . Vector3 ( ) ; const _colliderMaterial = new THREE . MeshBasicMaterial ( { visible : false } ) ; /**
 * An importer that imports a [[VRMSpringBoneManager]] from a VRM extension of a GLTF.
 */ export class VRMSpringBoneImporter { param gltf public async import ( gltf ) { const vrmExt = gltf . parser . json . extensions ?. VRM ; if ( ! vrmExt ) return null ; const schemaSecondaryAnimation = vrmExt . secondaryAnimation ; if ( ! schemaSecondaryAnimation ) return null ; const colliderGroups = await this . _importColliderMeshGroups ( gltf , schemaSecondaryAnimation ) ; const springBoneGroupList = await this . _importSpringBoneGroupList ( gltf , schemaSecondaryAnimation , colliderGroups ) ; return new VRMSpringBoneManager ( colliderGroups , springBoneGroupList ) ; } protected _createSpringBone ( bone , params = { } ) { return new VRMSpringBone ( bone , params ) ; } protected async _importSpringBoneGroupList ( gltf , schemaSecondaryAnimation , colliderGroups ) { const springBoneGroups = schemaSecondaryAnimation . boneGroups || [ ] ; const springBoneGroupList = [ ] ; await Promise . all ( springBoneGroups . map ( async ( vrmBoneGroup ) => { if ( vrmBoneGroup . stiffiness === undefined || vrmBoneGroup . gravityDir === undefined || vrmBoneGroup . gravityDir . x === undefined || vrmBoneGroup . gravityDir . y === undefined || vrmBoneGroup . gravityDir . z === undefined || vrmBoneGroup . gravityPower === undefined || vrmBoneGroup . dragForce === undefined || vrmBoneGroup . hitRadius === undefined || vrmBoneGroup . colliderGroups === undefined || vrmBoneGroup . bones === undefined || vrmBoneGroup . center === undefined ) { return ; } const stiffnessForce = vrmBoneGroup . stiffiness ; const gravityDir = new THREE . Vector3 ( vrmBoneGroup . gravityDir . x , vrmBoneGroup . gravityDir . y , - vrmBoneGroup . gravityDir . z ) ; const gravityPower = vrmBoneGroup . gravityPower ; const dragForce = vrmBoneGroup . dragForce ; const radius = vrmBoneGroup . hitRadius ; const colliders = [ ] ; vrmBoneGroup . colliderGroups . forEach ( ( colliderIndex ) => { colliders . push ( ... colliderGroups [ colliderIndex ] . colliders ) ; } ) ; const springBoneGroup = [ ] ; await Promise . all ( vrmBoneGroup . bones . map ( async ( nodeIndex ) => { const springRootBone = await gltf . parser . getDependency ( 'node' , nodeIndex ) ; const center = vrmBoneGroup . center ! !== - 1 ? await gltf . parser . getDependency ( 'node' , vrmBoneGroup . center ! ) : null ; if ( ! springRootBone ) { return ; } springRootBone . traverse ( ( bone ) => { const springBone = this . _createSpringBone ( bone , { radius , stiffnessForce , gravityDir , gravityPower , dragForce , colliders , center , } ) ; springBoneGroup . push ( springBone ) ; } ) ; } ) ) ; springBoneGroupList . push ( springBoneGroup ) ; } ) ) ; return springBoneGroupList ; } param gltf param schemaSecondaryAnimation protected async _importColliderMeshGroups ( gltf , schemaSecondaryAnimation ) { const vrmColliderGroups = schemaSecondaryAnimation . colliderGroups ; if ( vrmColliderGroups === undefined ) return [ ] ; const colliderGroups = [ ] ; vrmColliderGroups . forEach ( async ( colliderGroup ) => { if ( colliderGroup . node === undefined || colliderGroup . colliders === undefined ) { return ; } const bone = await gltf . parser . getDependency ( 'node' , colliderGroup . node ) ; const colliders = [ ] ; colliderGroup . colliders . forEach ( ( collider ) => { if ( collider . offset === undefined || collider . offset . x === undefined || collider . offset . y === undefined || collider . offset . z === undefined || collider . radius === undefined ) { return ; } const offset = _v3A . set ( collider . offset . x , collider . offset . y , - collider . offset . z ) ; const colliderMesh = this . _createColliderMesh ( collider . radius , offset ) ; bone . add ( colliderMesh ) ; colliders . push ( colliderMesh ) ; } ) ; const colliderMeshGroup = { node : colliderGroup . node , colliders , } ; colliderGroups . push ( colliderMeshGroup ) ; } ) ; return colliderGroups ; } param radius param offset protected _createColliderMesh ( radius , offset ) { const colliderMesh = new THREE . Mesh ( new THREE . SphereBufferGeometry ( radius , 8 , 4 ) , _colliderMaterial ) ; colliderMesh . position . copy ( offset ) ; colliderMesh . name = 'vrmColliderSphere' ; colliderMesh . geometry . computeBoundingSphere ( ) ; return colliderMesh ; } }