1- @@ - 1 , 729 + 0 , 0 @@
21import {
32 AnimationClip ,
43 ColorKeyframeTrack ,
@@ -33,14 +32,13 @@ const INTERPOLATION = {
3332// HACK monkey patching findNode to ensure we can map to other types required by KHR_animation_pointer.
3433const find = PropertyBinding . findNode ;
3534const _animationPointerDebug = false ;
36- let _havePatchedPropertyBindings = false ;
3735
3836/**
3937 * Animation Pointer Extension
4038 *
4139 * Draft Specification: https://github.com/ux3d/glTF/tree/extensions/KHR_animation_pointer/extensions/2.0/Khronos/KHR_animation_pointer
4240 */
43- class GLTFAnimationPointerExtension {
41+ export class GLTFAnimationPointerExtension {
4442
4543 constructor ( parser ) {
4644
@@ -57,107 +55,6 @@ class GLTFAnimationPointerExtension {
5755
5856 }
5957
60- _patchPropertyBindingFindNode ( ) {
61-
62- if ( _havePatchedPropertyBindings ) return ;
63- _havePatchedPropertyBindings = true ;
64-
65- // "node" is the Animator component in our case
66- // "path" is the animated property path, just with translated material names.
67- PropertyBinding . findNode = function ( node , path ) {
68-
69- if ( path . startsWith ( '.materials.' ) ) {
70-
71- if ( _animationPointerDebug ) console . log ( 'FIND' , path ) ;
72-
73- const remainingPath = path . substring ( '.materials.' . length ) . substring ( path . indexOf ( '.' ) ) ;
74- const nextIndex = remainingPath . indexOf ( '.' ) ;
75- const uuid = nextIndex < 0 ? remainingPath : remainingPath . substring ( 0 , nextIndex ) ;
76- let res = null ;
77- node . traverse ( x => {
78-
79- if ( res !== null || ( x . type !== 'Mesh' && x . type !== 'SkinnedMesh' ) ) return ;
80- if ( x [ 'material' ] && ( x [ 'material' ] . uuid === uuid || x [ 'material' ] . name === uuid ) ) {
81-
82- res = x [ 'material' ] ;
83- if ( _animationPointerDebug ) console . log ( res , remainingPath ) ;
84- if ( res !== null ) {
85-
86- if ( remainingPath . endsWith ( '.map' ) )
87- res = res [ 'map' ] ;
88- else if ( remainingPath . endsWith ( '.emissiveMap' ) )
89- res = res [ 'emissiveMap' ] ;
90-
91- // TODO other texture slots only make sense if three.js actually supports them
92- // (currently only .map can have repeat/offset)
93-
94- }
95-
96- }
97-
98- } ) ;
99-
100- return res ;
101-
102- } else if ( path . startsWith ( '.nodes.' ) || path . startsWith ( '.lights.' ) || path . startsWith ( '.cameras.' ) ) {
103-
104- const sections = path . split ( '.' ) ;
105- let currentTarget = undefined ;
106- for ( let i = 1 ; i < sections . length ; i ++ ) {
107-
108- const val = sections [ i ] ;
109- const isUUID = val . length == 36 ;
110- if ( isUUID ) {
111-
112- // access by UUID
113- currentTarget = node . getObjectByProperty ( 'uuid' , val ) ;
114-
115- } else if ( currentTarget && currentTarget [ val ] ) {
116-
117- // access by index
118- const index = Number . parseInt ( val ) ;
119- let key = val ;
120- if ( index >= 0 ) key = index ;
121- currentTarget = currentTarget [ key ] ;
122- if ( _animationPointerDebug )
123- console . log ( currentTarget ) ;
124-
125- } else {
126-
127- // access by node name
128- const foundNode = node . getObjectByName ( val ) ;
129-
130- if ( foundNode )
131- currentTarget = foundNode ;
132-
133- }
134-
135- }
136-
137- if ( ! currentTarget ) {
138-
139- const originalFindResult = find ( node , sections [ 2 ] ) ;
140-
141- if ( ! originalFindResult )
142- console . warn ( KHR_ANIMATION_POINTER + ': Property binding not found' , path , node , node . name , sections ) ;
143-
144- return originalFindResult ;
145-
146- }
147-
148- if ( _animationPointerDebug )
149- console . log ( 'NODE' , path , currentTarget ) ;
150-
151- return currentTarget ;
152-
153- }
154-
155- return find ( node , path ) ;
156-
157- } ;
158-
159- }
160-
16158 /* DUPLICATE of functionality in GLTFLoader */
16259 loadAnimationTargetFromChannel ( animationChannel ) {
16360
@@ -169,8 +66,7 @@ class GLTFAnimationPointerExtension {
16966
17067 loadAnimationTargetFromChannelWithAnimationPointer ( animationChannel ) {
17168
172- if ( ! this . _havePatchedPropertyBindings )
173- this . _patchPropertyBindingFindNode ( ) ;
69+ _ensurePropertyBindingPatch ( ) ;
17470
17571 const target = animationChannel . target ;
17672 const useExtension = target . extensions && target . extensions [ KHR_ANIMATION_POINTER ] && target . path && target . path === 'pointer' ;
@@ -727,4 +623,108 @@ class GLTFAnimationPointerExtension {
727623
728624}
729625
730- export { GLTFAnimationPointerExtension } ;
626+
627+
628+ let _havePatchedPropertyBindings = false ;
629+
630+ function _ensurePropertyBindingPatch ( ) {
631+
632+ if ( _havePatchedPropertyBindings ) return ;
633+ _havePatchedPropertyBindings = true ;
634+
635+ // "node" is the Animator component in our case
636+ // "path" is the animated property path, just with translated material names.
637+ PropertyBinding . findNode = function ( node , path ) {
638+
639+ if ( path . startsWith ( '.materials.' ) ) {
640+
641+ if ( _animationPointerDebug ) console . log ( 'FIND' , path ) ;
642+
643+ const remainingPath = path . substring ( '.materials.' . length ) . substring ( path . indexOf ( '.' ) ) ;
644+ const nextIndex = remainingPath . indexOf ( '.' ) ;
645+ const uuid = nextIndex < 0 ? remainingPath : remainingPath . substring ( 0 , nextIndex ) ;
646+ let res = null ;
647+ node . traverse ( x => {
648+
649+ if ( res !== null || ( x . type !== 'Mesh' && x . type !== 'SkinnedMesh' ) ) return ;
650+ if ( x [ 'material' ] && ( x [ 'material' ] . uuid === uuid || x [ 'material' ] . name === uuid ) ) {
651+
652+ res = x [ 'material' ] ;
653+ if ( _animationPointerDebug ) console . log ( res , remainingPath ) ;
654+ if ( res !== null ) {
655+
656+ if ( remainingPath . endsWith ( '.map' ) )
657+ res = res [ 'map' ] ;
658+ else if ( remainingPath . endsWith ( '.emissiveMap' ) )
659+ res = res [ 'emissiveMap' ] ;
660+
661+ // TODO other texture slots only make sense if three.js actually supports them
662+ // (currently only .map can have repeat/offset)
663+
664+ }
665+
666+ }
667+
668+ } ) ;
669+
670+ return res ;
671+
672+ } else if ( path . startsWith ( '.nodes.' ) || path . startsWith ( '.lights.' ) || path . startsWith ( '.cameras.' ) ) {
673+
674+ const sections = path . split ( '.' ) ;
675+ let currentTarget = undefined ;
676+ for ( let i = 1 ; i < sections . length ; i ++ ) {
677+
678+ const val = sections [ i ] ;
679+ const isUUID = val . length == 36 ;
680+ if ( isUUID ) {
681+
682+ // access by UUID
683+ currentTarget = node . getObjectByProperty ( 'uuid' , val ) ;
684+
685+ } else if ( currentTarget && currentTarget [ val ] ) {
686+
687+ // access by index
688+ const index = Number . parseInt ( val ) ;
689+ /** @type {string|number } */
690+ let key = val ;
691+ if ( index >= 0 ) key = index ;
692+ currentTarget = currentTarget [ key ] ;
693+ if ( _animationPointerDebug )
694+ console . log ( currentTarget ) ;
695+
696+ } else {
697+
698+ // access by node name
699+ const foundNode = node . getObjectByName ( val ) ;
700+
701+ if ( foundNode )
702+ currentTarget = foundNode ;
703+
704+ }
705+
706+ }
707+
708+ if ( ! currentTarget ) {
709+
710+ const originalFindResult = find ( node , sections [ 2 ] ) ;
711+
712+ if ( ! originalFindResult )
713+ console . warn ( KHR_ANIMATION_POINTER + ': Property binding not found' , path , node , node . name , sections ) ;
714+
715+ return originalFindResult ;
716+
717+ }
718+
719+ if ( _animationPointerDebug )
720+ console . log ( 'NODE' , path , currentTarget ) ;
721+
722+ return currentTarget ;
723+
724+ }
725+
726+ return find ( node , path ) ;
727+
728+ } ;
729+
730+ }
0 commit comments