1+ // Armature.js -- base skeleton abstraction across a well-known joint topology (independent of mesh)
2+
3+ import { _decoupledSkeletonClone } from './armature.utils.js' ;
4+ import remapJointNames from './remapJointNames.js' ;
5+ import { NamedJointWrappers } from './NamedJointWrappers.js' ;
6+ import { AutoIKChain , walkBoneChain } from './AutoIKChain.js' ;
7+ import SkeletonMetrics from './SkeletonMetrics.js' ;
8+
9+ class Armature {
10+ static get version ( ) { return '0.0.0a' ; }
11+ constructor ( skeleton , options ) {
12+ this . options = options ;
13+ this . skeleton = skeleton ;
14+ this . originalSkeleton = _decoupledSkeletonClone ( skeleton , new THREE . Group ( ) ) ;
15+ this . bones = remapJointNames ( this . skeleton , options . remapper ) ;
16+ this . rootBone = this . bones . Hips ;
17+ this . armatureObject = this . rootBone . parent ;
18+ this . bones . Armature = this . bones . Armature || this . armatureObject ;
19+ //this.bones.Armature.rotation.order = 'YXZ';
20+ this . bones . Hips . rotation . order = 'YXZ' ;
21+ this . bones . Head . rotation . order = 'YXZ' ;
22+
23+ //this.armatureBone =
24+ this . boneNames = Object . keys ( this . bones ) ;
25+ this . metrics = new SkeletonMetrics ( skeleton ) ;
26+ this . backup = _decoupledSkeletonClone ( skeleton , new THREE . Group ( ) ) ;
27+ this . backup . metrics = new SkeletonMetrics ( this . backup ) ;
28+
29+ this . virtual = new THREE . Object3D ( ) ;
30+ this . virtual . rotation . order = 'YXZ' ;
31+
32+ const idNames = this . boneNames . reduce ( ( out , x ) => {
33+ out [ x . replace ( / ^ ( .) ( .* ) $ / , ( _ , ch , rest ) => ( ch . toLowerCase ( ) + rest ) ) ] = x ;
34+ return out ;
35+ } , { } ) ;
36+ Object . assign ( this , new NamedJointWrappers ( skeleton , idNames ) ) ;
37+ }
38+
39+ walk ( a , b , silent = false ) {
40+ var bc = walkBoneChain ( this . get ( a ) , this . get ( b ) ) ;
41+ if ( ! silent && ! bc . valid ) {
42+ debugger ;
43+ throw new Error ( 'bad chain: ' + [ a , b ] . join ( '=>' ) ) ;
44+ }
45+ return bc ;
46+ }
47+
48+ // experimental support for "tearing off" subskeleton chains
49+ virtualSegment ( from , to ) {
50+ var container = {
51+ name : 'virtualArmatureSegment' ,
52+ id : - 1 ,
53+ uuid : - 1 ,
54+ __proto__ : new THREE . Object3D ( )
55+ } ;
56+ //var solo = _decoupledSkeletonClone(this.skeleton, new THREE.Group());
57+ var bc = this . walk ( this . get ( from ) , this . get ( to ) ) ;
58+ if ( bc . head . parent ) {
59+ bc . head . parent . getWorldPosition ( container . position ) ;
60+ bc . head . parent . getWorldQuaternion ( container . quaternion ) ;
61+ bc . head . parent . getWorldScale ( container . scale ) ;
62+ container . id = bc . head . parent . id ;
63+ container . uuid = bc . head . parent . uuid ;
64+ }
65+ var keep = bc . lineage . reduce ( function ( out , x ) { out [ x . uuid ] = true ; return out ; } , { } ) ;
66+ //console.info('virtualSegment', keep, bc.lineage);
67+ var proxies = { } ;
68+ var byname = { } ;
69+ var vbones = this . skeleton . bones
70+ . map ( ( x , i ) => { return byname [ x . name ] = proxies [ x . uuid ] = {
71+ parent : keep [ x . parent && x . parent . uuid ] ? x . parent : container ,
72+ $boneInverse : this . skeleton . boneInverses [ i ] ,
73+ __proto__ : x ,
74+ } } )
75+ . filter ( ( x ) => keep [ x . uuid ] )
76+ . map ( ( x ) => {
77+ x . parent = proxies [ x . parent && x . parent . uuid ] || container ;
78+ x . children = x . children . filter ( ( c ) => keep [ c . uuid ] ) . map ( ( c ) => proxies [ c . uuid ] ) ;
79+ if ( x . parent === container ) container . children . push ( x ) ;
80+ return x ;
81+ } )
82+ var vboneInverses = vbones . map ( ( b ) => b . $boneInverse ) ;
83+ //console.info('//virtualSegment', vbones.map((x)=>[x.name,x.children.length].join('#')));
84+
85+ return Object . assign ( new THREE . Skeleton ( vbones , vboneInverses ) , {
86+ toString : function ( ) { return `[PartialSkeleton head=${ this . head . name } tail=${ this . tail . name } bones=${ this . bones . length } ]` ; } ,
87+ container : container ,
88+ head : proxies [ bc . head . uuid ] ,
89+ tail : proxies [ bc . tail . uuid ] ,
90+ lineage : bc . lineage . map ( ( x ) => proxies [ x . uuid ] ) ,
91+ } ) ;
92+ }
93+
94+ // helper methods
95+ get ( name ) {
96+ if ( typeof name === 'string' ) return this . bones [ name ] ;
97+ if ( name && name . isBone ) return name ;
98+ return null ;
99+ }
100+ inv ( name ) {
101+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
102+ if ( ~ i ) { return this . skeleton . boneInverses [ i ] ; }
103+ return null ;
104+ }
105+ setInv ( name , mat ) {
106+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
107+ if ( ! ~ i ) return null ;
108+ this . skeleton . boneInverses [ i ] . copy ( mat ) ;
109+ }
110+ setUnInv ( name , mat ) {
111+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
112+ if ( ! ~ i ) return null ;
113+ this . skeleton . boneInverses [ i ] . copy ( new THREE . Matrix4 ( ) . getInverse ( mat ) ) ;
114+ }
115+ mat ( name ) {
116+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
117+ if ( ! ~ i ) return null ;
118+ return new THREE . Matrix4 ( ) . copy ( { elements :this . skeleton . boneMatrices . slice ( i * 16 , i * 16 + 16 ) } ) ;
119+ }
120+ img ( name ) {
121+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
122+ if ( ! ~ i ) return null ;
123+ return new THREE . Matrix4 ( ) . copy ( { elements :this . skeleton . boneTexture . image . data . slice ( i * 16 , i * 16 + 16 ) } ) ;
124+ }
125+ setMat ( name , mat ) {
126+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
127+ if ( ! ~ i ) return null ;
128+ for ( var j = 0 ; j < 16 ; j ++ ) this . skeleton . boneMatrices [ i * 16 + j ] = mat . elements [ j ] ;
129+ }
130+ setImg ( name , mat ) {
131+ var i = this . skeleton . bones . indexOf ( this . get ( name ) ) ;
132+ if ( ! ~ i ) return null ;
133+ for ( var j = 0 ; j < 16 ; j ++ ) this . skeleton . boneTexture . image . data [ i * 16 + j ] = mat . elements [ j ] ;
134+ }
135+ getLocalRotation ( name ) {
136+ var bone = this . get ( name ) ;
137+ var orientation = bone . getWorldQuaternion ( new THREE . Quaternion ( ) ) ;
138+ var parentOrientation = bone . parent . getWorldQuaternion ( new THREE . Quaternion ( ) ) ;
139+ return parentOrientation . inverse ( ) . multiply ( orientation ) ;
140+ }
141+ getBindPose ( name ) {
142+ return this . backup [ name ] ;
143+ }
144+ } ;
145+
146+ export default Armature ;
147+ export { Armature } ;
148+ try { Object . assign ( self , { Armature } ) ; } catch ( e ) { }
0 commit comments