@needle-tools/engine 3.28.7-beta → 3.28.7-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2259 -2256
- package/LICENSE.md +10 -10
- package/README.md +52 -52
- package/dist/needle-engine.js +9 -12
- package/dist/needle-engine.light.js +9 -12
- package/dist/needle-engine.light.min.js +8 -11
- package/dist/needle-engine.light.umd.cjs +8 -11
- package/dist/needle-engine.min.js +8 -11
- package/dist/needle-engine.umd.cjs +8 -11
- package/lib/engine/api.d.ts +52 -52
- package/lib/engine/api.js +51 -51
- package/lib/engine/assets/index.d.ts +1 -1
- package/lib/engine/assets/index.js +4 -4
- package/lib/engine/codegen/register_types.d.ts +1 -1
- package/lib/engine/codegen/register_types.js +439 -439
- package/lib/engine/debug/debug.d.ts +12 -12
- package/lib/engine/debug/debug.js +26 -26
- package/lib/engine/debug/debug_console.d.ts +2 -2
- package/lib/engine/debug/debug_console.js +204 -204
- package/lib/engine/debug/debug_overlay.d.ts +10 -10
- package/lib/engine/debug/debug_overlay.js +277 -277
- package/lib/engine/debug/index.d.ts +1 -1
- package/lib/engine/debug/index.js +1 -1
- package/lib/engine/engine_addressables.d.ts +75 -75
- package/lib/engine/engine_addressables.js +441 -441
- package/lib/engine/engine_application.d.ts +19 -19
- package/lib/engine/engine_application.js +45 -45
- package/lib/engine/engine_assetdatabase.d.ts +25 -25
- package/lib/engine/engine_assetdatabase.js +341 -341
- package/lib/engine/engine_camera.d.ts +6 -6
- package/lib/engine/engine_camera.js +23 -23
- package/lib/engine/engine_components.d.ts +17 -17
- package/lib/engine/engine_components.js +273 -273
- package/lib/engine/engine_components_internal.d.ts +11 -11
- package/lib/engine/engine_components_internal.js +41 -41
- package/lib/engine/engine_constants.d.ts +5 -5
- package/lib/engine/engine_constants.js +32 -32
- package/lib/engine/engine_context.d.ts +269 -269
- package/lib/engine/engine_context.js +1242 -1242
- package/lib/engine/engine_context_registry.d.ts +50 -50
- package/lib/engine/engine_context_registry.js +89 -89
- package/lib/engine/engine_coroutine.d.ts +4 -4
- package/lib/engine/engine_coroutine.js +21 -21
- package/lib/engine/engine_create_objects.d.ts +13 -13
- package/lib/engine/engine_create_objects.js +33 -33
- package/lib/engine/engine_default_parameters.d.ts +2 -2
- package/lib/engine/engine_default_parameters.js +3 -3
- package/lib/engine/engine_editor-sync.d.ts +17 -17
- package/lib/engine/engine_editor-sync.js +7 -7
- package/lib/engine/engine_element.d.ts +55 -55
- package/lib/engine/engine_element.js +559 -559
- package/lib/engine/engine_element_attributes.d.ts +49 -49
- package/lib/engine/engine_element_attributes.js +1 -1
- package/lib/engine/engine_element_extras.d.ts +6 -6
- package/lib/engine/engine_element_extras.js +13 -13
- package/lib/engine/engine_element_loading.d.ts +40 -40
- package/lib/engine/engine_element_loading.js +312 -312
- package/lib/engine/engine_element_overlay.d.ts +19 -19
- package/lib/engine/engine_element_overlay.js +143 -143
- package/lib/engine/engine_fileloader.d.ts +3 -3
- package/lib/engine/engine_fileloader.js +7 -7
- package/lib/engine/engine_gameobject.d.ts +39 -39
- package/lib/engine/engine_gameobject.js +559 -559
- package/lib/engine/engine_generic_utils.d.ts +1 -1
- package/lib/engine/engine_generic_utils.js +13 -13
- package/lib/engine/engine_gizmos.d.ts +26 -26
- package/lib/engine/engine_gizmos.js +282 -282
- package/lib/engine/engine_gltf.d.ts +13 -13
- package/lib/engine/engine_gltf.js +15 -15
- package/lib/engine/engine_gltf_builtin_components.d.ts +7 -7
- package/lib/engine/engine_gltf_builtin_components.js +298 -298
- package/lib/engine/engine_hot_reload.d.ts +5 -5
- package/lib/engine/engine_hot_reload.js +182 -182
- package/lib/engine/engine_input.d.ts +129 -129
- package/lib/engine/engine_input.js +799 -799
- package/lib/engine/engine_input_utils.d.ts +2 -2
- package/lib/engine/engine_input_utils.js +22 -22
- package/lib/engine/engine_instancing.d.ts +16 -16
- package/lib/engine/engine_instancing.js +36 -36
- package/lib/engine/engine_license.d.ts +4 -4
- package/lib/engine/engine_license.js +398 -398
- package/lib/engine/engine_lifecycle_api.d.ts +14 -14
- package/lib/engine/engine_lifecycle_api.js +24 -24
- package/lib/engine/engine_lifecycle_functions_internal.d.ts +6 -6
- package/lib/engine/engine_lifecycle_functions_internal.js +28 -28
- package/lib/engine/engine_lightdata.d.ts +23 -23
- package/lib/engine/engine_lightdata.js +86 -86
- package/lib/engine/engine_loaders.d.ts +7 -7
- package/lib/engine/engine_loaders.js +69 -69
- package/lib/engine/engine_mainloop_utils.d.ts +13 -13
- package/lib/engine/engine_mainloop_utils.js +426 -426
- package/lib/engine/engine_math.d.ts +43 -43
- package/lib/engine/engine_math.js +147 -147
- package/lib/engine/engine_networking.d.ts +176 -176
- package/lib/engine/engine_networking.js +649 -649
- package/lib/engine/engine_networking_auto.d.ts +24 -24
- package/lib/engine/engine_networking_auto.js +324 -324
- package/lib/engine/engine_networking_files.d.ts +23 -23
- package/lib/engine/engine_networking_files.js +176 -176
- package/lib/engine/engine_networking_files_default_components.d.ts +3 -3
- package/lib/engine/engine_networking_files_default_components.js +39 -39
- package/lib/engine/engine_networking_instantiate.d.ts +39 -39
- package/lib/engine/engine_networking_instantiate.js +302 -302
- package/lib/engine/engine_networking_peer.d.ts +15 -15
- package/lib/engine/engine_networking_peer.js +132 -132
- package/lib/engine/engine_networking_streams.d.ts +90 -90
- package/lib/engine/engine_networking_streams.js +428 -428
- package/lib/engine/engine_networking_types.d.ts +14 -14
- package/lib/engine/engine_networking_types.js +7 -7
- package/lib/engine/engine_networking_utils.d.ts +2 -2
- package/lib/engine/engine_networking_utils.js +20 -20
- package/lib/engine/engine_patcher.d.ts +10 -10
- package/lib/engine/engine_patcher.js +142 -142
- package/lib/engine/engine_physics.d.ts +115 -115
- package/lib/engine/engine_physics.js +228 -228
- package/lib/engine/engine_physics.types.d.ts +37 -37
- package/lib/engine/engine_physics.types.js +33 -33
- package/lib/engine/engine_physics_rapier.d.ts +112 -112
- package/lib/engine/engine_physics_rapier.js +1266 -1266
- package/lib/engine/engine_playerview.d.ts +26 -26
- package/lib/engine/engine_playerview.js +64 -64
- package/lib/engine/engine_scenelighting.d.ts +74 -74
- package/lib/engine/engine_scenelighting.js +285 -285
- package/lib/engine/engine_scenetools.d.ts +35 -35
- package/lib/engine/engine_scenetools.js +212 -212
- package/lib/engine/engine_serialization.d.ts +4 -4
- package/lib/engine/engine_serialization.js +4 -4
- package/lib/engine/engine_serialization_builtin_serializer.d.ts +62 -62
- package/lib/engine/engine_serialization_builtin_serializer.js +369 -369
- package/lib/engine/engine_serialization_core.d.ts +84 -84
- package/lib/engine/engine_serialization_core.js +576 -576
- package/lib/engine/engine_serialization_decorator.d.ts +15 -15
- package/lib/engine/engine_serialization_decorator.js +54 -54
- package/lib/engine/engine_setup.d.ts +1 -1
- package/lib/engine/engine_setup.js +2 -2
- package/lib/engine/engine_shaders.d.ts +31 -31
- package/lib/engine/engine_shaders.js +229 -229
- package/lib/engine/engine_shims.d.ts +3 -3
- package/lib/engine/engine_shims.js +22 -22
- package/lib/engine/engine_texture.d.ts +20 -20
- package/lib/engine/engine_texture.js +57 -57
- package/lib/engine/engine_three_utils.d.ts +51 -51
- package/lib/engine/engine_three_utils.js +342 -342
- package/lib/engine/engine_time.d.ts +19 -19
- package/lib/engine/engine_time.js +47 -47
- package/lib/engine/engine_types.d.ts +358 -358
- package/lib/engine/engine_types.js +72 -72
- package/lib/engine/engine_typestore.d.ts +16 -16
- package/lib/engine/engine_typestore.js +35 -35
- package/lib/engine/engine_util_decorator.d.ts +12 -12
- package/lib/engine/engine_util_decorator.js +115 -115
- package/lib/engine/engine_utils.d.ts +104 -104
- package/lib/engine/engine_utils.js +518 -518
- package/lib/engine/engine_utils_screenshot.d.ts +10 -10
- package/lib/engine/engine_utils_screenshot.js +70 -70
- package/lib/engine/engine_web_api.d.ts +12 -12
- package/lib/engine/engine_web_api.js +112 -112
- package/lib/engine/extensions/EXT_texture_exr.d.ts +8 -8
- package/lib/engine/extensions/EXT_texture_exr.js +32 -32
- package/lib/engine/extensions/NEEDLE_animator_controller_model.d.ts +116 -116
- package/lib/engine/extensions/NEEDLE_animator_controller_model.js +91 -91
- package/lib/engine/extensions/NEEDLE_components.d.ts +33 -33
- package/lib/engine/extensions/NEEDLE_components.js +206 -206
- package/lib/engine/extensions/NEEDLE_gameobject_data.d.ts +10 -10
- package/lib/engine/extensions/NEEDLE_gameobject_data.js +57 -57
- package/lib/engine/extensions/NEEDLE_lighting_settings.d.ts +38 -38
- package/lib/engine/extensions/NEEDLE_lighting_settings.js +183 -183
- package/lib/engine/extensions/NEEDLE_lightmaps.d.ts +18 -18
- package/lib/engine/extensions/NEEDLE_lightmaps.js +108 -108
- package/lib/engine/extensions/NEEDLE_persistent_assets.d.ts +11 -11
- package/lib/engine/extensions/NEEDLE_persistent_assets.js +63 -63
- package/lib/engine/extensions/NEEDLE_progressive.d.ts +41 -41
- package/lib/engine/extensions/NEEDLE_progressive.js +366 -366
- package/lib/engine/extensions/NEEDLE_render_objects.d.ts +13 -13
- package/lib/engine/extensions/NEEDLE_render_objects.js +159 -159
- package/lib/engine/extensions/NEEDLE_techniques_webgl.d.ts +39 -39
- package/lib/engine/extensions/NEEDLE_techniques_webgl.js +544 -544
- package/lib/engine/extensions/extension_resolver.d.ts +4 -4
- package/lib/engine/extensions/extension_resolver.js +1 -1
- package/lib/engine/extensions/extension_utils.d.ts +2 -2
- package/lib/engine/extensions/extension_utils.js +140 -140
- package/lib/engine/extensions/extensions.d.ts +21 -21
- package/lib/engine/extensions/extensions.js +94 -94
- package/lib/engine/extensions/index.d.ts +5 -5
- package/lib/engine/extensions/index.js +5 -5
- package/lib/engine/extensions/usage_tracker.d.ts +13 -13
- package/lib/engine/extensions/usage_tracker.js +61 -61
- package/lib/engine/js-extensions/Camera.d.ts +1 -1
- package/lib/engine/js-extensions/Camera.js +36 -36
- package/lib/engine/js-extensions/Layers.d.ts +3 -3
- package/lib/engine/js-extensions/Layers.js +19 -19
- package/lib/engine/js-extensions/index.d.ts +2 -2
- package/lib/engine/js-extensions/index.js +2 -2
- package/lib/engine/shaders/shaderData.d.ts +55 -55
- package/lib/engine/shaders/shaderData.js +58 -58
- package/lib/engine/tests/test_utils.d.ts +2 -2
- package/lib/engine/tests/test_utils.js +53 -53
- package/lib/engine-components/AlignmentConstraint.d.ts +10 -10
- package/lib/engine-components/AlignmentConstraint.js +39 -39
- package/lib/engine-components/Animation.d.ts +53 -53
- package/lib/engine-components/Animation.js +333 -333
- package/lib/engine-components/AnimationCurve.d.ts +16 -16
- package/lib/engine-components/AnimationCurve.js +97 -97
- package/lib/engine-components/AnimationUtils.d.ts +8 -8
- package/lib/engine-components/AnimationUtils.js +110 -110
- package/lib/engine-components/Animator.d.ts +81 -81
- package/lib/engine-components/Animator.js +229 -229
- package/lib/engine-components/AnimatorController.d.ts +57 -57
- package/lib/engine-components/AnimatorController.js +887 -887
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/AudioListener.d.ts +7 -7
- package/lib/engine-components/AudioListener.js +30 -30
- package/lib/engine-components/AudioSource.d.ts +61 -61
- package/lib/engine-components/AudioSource.js +422 -422
- package/lib/engine-components/AvatarLoader.d.ts +19 -19
- package/lib/engine-components/AvatarLoader.js +173 -173
- package/lib/engine-components/AxesHelper.d.ts +9 -9
- package/lib/engine-components/AxesHelper.js +44 -44
- package/lib/engine-components/BasicIKConstraint.d.ts +9 -9
- package/lib/engine-components/BasicIKConstraint.js +43 -43
- package/lib/engine-components/BoxHelperComponent.d.ts +16 -16
- package/lib/engine-components/BoxHelperComponent.js +89 -89
- package/lib/engine-components/Camera.d.ts +70 -70
- package/lib/engine-components/Camera.js +450 -450
- package/lib/engine-components/CameraUtils.d.ts +1 -1
- package/lib/engine-components/CameraUtils.js +77 -77
- package/lib/engine-components/CharacterController.d.ts +46 -46
- package/lib/engine-components/CharacterController.js +227 -227
- package/lib/engine-components/Collider.d.ts +46 -46
- package/lib/engine-components/Collider.js +153 -153
- package/lib/engine-components/Component.d.ts +228 -228
- package/lib/engine-components/Component.js +541 -541
- package/lib/engine-components/ContactShadows.d.ts +23 -23
- package/lib/engine-components/ContactShadows.js +233 -233
- package/lib/engine-components/DeleteBox.d.ts +9 -9
- package/lib/engine-components/DeleteBox.js +30 -30
- package/lib/engine-components/DeviceFlag.d.ts +12 -12
- package/lib/engine-components/DeviceFlag.js +43 -43
- package/lib/engine-components/DragControls.d.ts +51 -51
- package/lib/engine-components/DragControls.js +516 -516
- package/lib/engine-components/DropListener.d.ts +15 -15
- package/lib/engine-components/DropListener.js +120 -120
- package/lib/engine-components/Duplicatable.d.ts +16 -16
- package/lib/engine-components/Duplicatable.js +150 -150
- package/lib/engine-components/EventList.d.ts +28 -28
- package/lib/engine-components/EventList.js +105 -105
- package/lib/engine-components/EventTrigger.d.ts +12 -12
- package/lib/engine-components/EventTrigger.js +50 -50
- package/lib/engine-components/EventType.d.ts +19 -19
- package/lib/engine-components/EventType.js +71 -71
- package/lib/engine-components/FlyControls.d.ts +7 -7
- package/lib/engine-components/FlyControls.js +25 -25
- package/lib/engine-components/Fog.d.ts +20 -20
- package/lib/engine-components/Fog.js +60 -60
- package/lib/engine-components/Gizmos.d.ts +12 -12
- package/lib/engine-components/Gizmos.js +60 -60
- package/lib/engine-components/GridHelper.d.ts +12 -12
- package/lib/engine-components/GridHelper.js +47 -47
- package/lib/engine-components/GroundProjection.d.ts +21 -21
- package/lib/engine-components/GroundProjection.js +97 -97
- package/lib/engine-components/Interactable.d.ts +10 -10
- package/lib/engine-components/Interactable.js +11 -11
- package/lib/engine-components/Joints.d.ts +19 -19
- package/lib/engine-components/Joints.js +51 -51
- package/lib/engine-components/LODGroup.d.ts +30 -30
- package/lib/engine-components/LODGroup.js +145 -145
- package/lib/engine-components/Light.d.ts +75 -75
- package/lib/engine-components/Light.js +475 -475
- package/lib/engine-components/LookAtConstraint.d.ts +7 -7
- package/lib/engine-components/LookAtConstraint.js +17 -17
- package/lib/engine-components/NestedGltf.d.ts +11 -11
- package/lib/engine-components/NestedGltf.js +74 -74
- package/lib/engine-components/Networking.d.ts +11 -11
- package/lib/engine-components/Networking.js +70 -70
- package/lib/engine-components/OffsetConstraint.d.ts +14 -14
- package/lib/engine-components/OffsetConstraint.js +65 -65
- package/lib/engine-components/OrbitControls.d.ts +111 -111
- package/lib/engine-components/OrbitControls.js +646 -646
- package/lib/engine-components/ParticleSystem.d.ts +145 -145
- package/lib/engine-components/ParticleSystem.js +1077 -1077
- package/lib/engine-components/ParticleSystemModules.d.ts +489 -489
- package/lib/engine-components/ParticleSystemModules.js +1667 -1667
- package/lib/engine-components/ParticleSystemSubEmitter.d.ts +25 -25
- package/lib/engine-components/ParticleSystemSubEmitter.js +86 -86
- package/lib/engine-components/PlayerColor.d.ts +13 -13
- package/lib/engine-components/PlayerColor.js +83 -83
- package/lib/engine-components/ReflectionProbe.d.ts +22 -22
- package/lib/engine-components/ReflectionProbe.js +181 -181
- package/lib/engine-components/Renderer.d.ts +112 -112
- package/lib/engine-components/Renderer.js +1029 -1029
- package/lib/engine-components/RendererLightmap.d.ts +19 -19
- package/lib/engine-components/RendererLightmap.js +127 -127
- package/lib/engine-components/RigidBody.d.ts +120 -120
- package/lib/engine-components/RigidBody.js +452 -452
- package/lib/engine-components/SceneSwitcher.d.ts +72 -72
- package/lib/engine-components/SceneSwitcher.js +583 -583
- package/lib/engine-components/ScreenCapture.d.ts +64 -64
- package/lib/engine-components/ScreenCapture.js +405 -405
- package/lib/engine-components/ShadowCatcher.d.ts +18 -18
- package/lib/engine-components/ShadowCatcher.js +144 -144
- package/lib/engine-components/Skybox.d.ts +23 -23
- package/lib/engine-components/Skybox.js +287 -287
- package/lib/engine-components/SmoothFollow.d.ts +14 -14
- package/lib/engine-components/SmoothFollow.js +63 -63
- package/lib/engine-components/SpatialTrigger.d.ts +27 -27
- package/lib/engine-components/SpatialTrigger.js +144 -144
- package/lib/engine-components/SpectatorCamera.d.ts +45 -45
- package/lib/engine-components/SpectatorCamera.js +593 -593
- package/lib/engine-components/SpriteRenderer.d.ts +48 -48
- package/lib/engine-components/SpriteRenderer.js +257 -257
- package/lib/engine-components/SyncedCamera.d.ts +27 -27
- package/lib/engine-components/SyncedCamera.js +187 -187
- package/lib/engine-components/SyncedRoom.d.ts +24 -24
- package/lib/engine-components/SyncedRoom.js +162 -162
- package/lib/engine-components/SyncedTransform.d.ts +35 -35
- package/lib/engine-components/SyncedTransform.js +265 -265
- package/lib/engine-components/TestRunner.d.ts +13 -13
- package/lib/engine-components/TestRunner.js +99 -99
- package/lib/engine-components/TransformGizmo.d.ts +16 -16
- package/lib/engine-components/TransformGizmo.js +148 -148
- package/lib/engine-components/VideoPlayer.d.ts +86 -86
- package/lib/engine-components/VideoPlayer.js +792 -792
- package/lib/engine-components/Voip.d.ts +29 -29
- package/lib/engine-components/Voip.js +203 -203
- package/lib/engine-components/XRFlag.d.ts +33 -33
- package/lib/engine-components/XRFlag.js +128 -128
- package/lib/engine-components/api.d.ts +15 -15
- package/lib/engine-components/api.js +15 -15
- package/lib/engine-components/avatar/AvatarBlink_Simple.d.ts +10 -10
- package/lib/engine-components/avatar/AvatarBlink_Simple.js +75 -75
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.d.ts +13 -13
- package/lib/engine-components/avatar/AvatarEyeLook_Rotation.js +74 -74
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.d.ts +27 -27
- package/lib/engine-components/avatar/Avatar_Brain_LookAt.js +119 -119
- package/lib/engine-components/avatar/Avatar_MouthShapes.d.ts +13 -13
- package/lib/engine-components/avatar/Avatar_MouthShapes.js +78 -78
- package/lib/engine-components/avatar/Avatar_MustacheShake.d.ts +8 -8
- package/lib/engine-components/avatar/Avatar_MustacheShake.js +28 -28
- package/lib/engine-components/codegen/components.d.ts +216 -216
- package/lib/engine-components/codegen/components.js +217 -217
- package/lib/engine-components/debug/LogStats.d.ts +5 -5
- package/lib/engine-components/debug/LogStats.js +18 -18
- package/lib/engine-components/export/gltf/GltfExport.d.ts +25 -25
- package/lib/engine-components/export/gltf/GltfExport.js +215 -215
- package/lib/engine-components/export/index.d.ts +1 -1
- package/lib/engine-components/export/index.js +1 -1
- package/lib/engine-components/export/usdz/Extension.d.ts +10 -10
- package/lib/engine-components/export/usdz/Extension.js +1 -1
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +114 -114
- package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +1211 -1211
- package/lib/engine-components/export/usdz/USDZExporter.d.ts +59 -59
- package/lib/engine-components/export/usdz/USDZExporter.js +450 -450
- package/lib/engine-components/export/usdz/extensions/Animation.d.ts +69 -69
- package/lib/engine-components/export/usdz/extensions/Animation.js +650 -650
- package/lib/engine-components/export/usdz/extensions/DocumentExtension.d.ts +5 -5
- package/lib/engine-components/export/usdz/extensions/DocumentExtension.js +6 -6
- package/lib/engine-components/export/usdz/extensions/USDZText.d.ts +55 -55
- package/lib/engine-components/export/usdz/extensions/USDZText.js +246 -246
- package/lib/engine-components/export/usdz/extensions/USDZUI.d.ts +8 -8
- package/lib/engine-components/export/usdz/extensions/USDZUI.js +100 -100
- package/lib/engine-components/export/usdz/extensions/behavior/Actions.d.ts +30 -30
- package/lib/engine-components/export/usdz/extensions/behavior/Actions.js +88 -88
- package/lib/engine-components/export/usdz/extensions/behavior/AudioExtension.d.ts +9 -9
- package/lib/engine-components/export/usdz/extensions/behavior/AudioExtension.js +52 -52
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.d.ts +22 -22
- package/lib/engine-components/export/usdz/extensions/behavior/Behaviour.js +134 -134
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.d.ts +126 -126
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +824 -824
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.d.ts +133 -133
- package/lib/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.js +464 -464
- package/lib/engine-components/export/usdz/index.d.ts +3 -3
- package/lib/engine-components/export/usdz/index.js +2 -2
- package/lib/engine-components/export/usdz/utils/animationutils.d.ts +3 -3
- package/lib/engine-components/export/usdz/utils/animationutils.js +85 -85
- package/lib/engine-components/export/usdz/utils/quicklook.d.ts +2 -2
- package/lib/engine-components/export/usdz/utils/quicklook.js +35 -35
- package/lib/engine-components/export/usdz/utils/timeutils.d.ts +1 -1
- package/lib/engine-components/export/usdz/utils/timeutils.js +14 -14
- package/lib/engine-components/js-extensions/ExtensionUtils.d.ts +6 -6
- package/lib/engine-components/js-extensions/ExtensionUtils.js +65 -65
- package/lib/engine-components/js-extensions/Object3D.d.ts +2 -2
- package/lib/engine-components/js-extensions/Object3D.js +140 -140
- package/lib/engine-components/js-extensions/RGBAColor.d.ts +14 -14
- package/lib/engine-components/js-extensions/RGBAColor.js +49 -49
- package/lib/engine-components/js-extensions/index.d.ts +3 -3
- package/lib/engine-components/js-extensions/index.js +3 -3
- package/lib/engine-components/postprocessing/Effects/Antialiasing.d.ts +13 -13
- package/lib/engine-components/postprocessing/Effects/Antialiasing.js +45 -45
- package/lib/engine-components/postprocessing/Effects/Bloom.d.ts +12 -12
- package/lib/engine-components/postprocessing/Effects/Bloom.js +77 -77
- package/lib/engine-components/postprocessing/Effects/ChromaticAberration.d.ts +8 -8
- package/lib/engine-components/postprocessing/Effects/ChromaticAberration.js +38 -38
- package/lib/engine-components/postprocessing/Effects/ColorAdjustments.d.ts +12 -12
- package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js +81 -81
- package/lib/engine-components/postprocessing/Effects/DepthOfField.d.ts +21 -21
- package/lib/engine-components/postprocessing/Effects/DepthOfField.js +97 -97
- package/lib/engine-components/postprocessing/Effects/Pixelation.d.ts +7 -7
- package/lib/engine-components/postprocessing/Effects/Pixelation.js +28 -28
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.d.ts +13 -13
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js +86 -86
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.d.ts +24 -24
- package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js +94 -94
- package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.d.ts +13 -13
- package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js +62 -62
- package/lib/engine-components/postprocessing/Effects/Tonemapping.d.ts +16 -16
- package/lib/engine-components/postprocessing/Effects/Tonemapping.js +51 -51
- package/lib/engine-components/postprocessing/Effects/Vignette.d.ts +11 -11
- package/lib/engine-components/postprocessing/Effects/Vignette.js +56 -56
- package/lib/engine-components/postprocessing/PostProcessingEffect.d.ts +33 -33
- package/lib/engine-components/postprocessing/PostProcessingEffect.js +126 -126
- package/lib/engine-components/postprocessing/PostProcessingHandler.d.ts +22 -22
- package/lib/engine-components/postprocessing/PostProcessingHandler.js +201 -201
- package/lib/engine-components/postprocessing/Volume.d.ts +25 -25
- package/lib/engine-components/postprocessing/Volume.js +193 -193
- package/lib/engine-components/postprocessing/VolumeParameter.d.ts +22 -22
- package/lib/engine-components/postprocessing/VolumeParameter.js +80 -80
- package/lib/engine-components/postprocessing/VolumeProfile.d.ts +7 -7
- package/lib/engine-components/postprocessing/VolumeProfile.js +41 -41
- package/lib/engine-components/postprocessing/index.d.ts +4 -4
- package/lib/engine-components/postprocessing/index.js +4 -4
- package/lib/engine-components/timeline/PlayableDirector.d.ts +107 -107
- package/lib/engine-components/timeline/PlayableDirector.js +624 -624
- package/lib/engine-components/timeline/SignalAsset.d.ts +18 -18
- package/lib/engine-components/timeline/SignalAsset.js +124 -124
- package/lib/engine-components/timeline/TimelineModels.d.ts +88 -88
- package/lib/engine-components/timeline/TimelineModels.js +22 -22
- package/lib/engine-components/timeline/TimelineTracks.d.ts +90 -90
- package/lib/engine-components/timeline/TimelineTracks.js +825 -825
- package/lib/engine-components/timeline/index.d.ts +4 -4
- package/lib/engine-components/timeline/index.js +3 -3
- package/lib/engine-components/ui/BaseUIComponent.d.ts +31 -31
- package/lib/engine-components/ui/BaseUIComponent.js +161 -161
- package/lib/engine-components/ui/Button.d.ts +56 -56
- package/lib/engine-components/ui/Button.js +282 -282
- package/lib/engine-components/ui/Canvas.d.ts +67 -67
- package/lib/engine-components/ui/Canvas.js +382 -382
- package/lib/engine-components/ui/CanvasGroup.d.ts +15 -15
- package/lib/engine-components/ui/CanvasGroup.js +53 -53
- package/lib/engine-components/ui/EventSystem.d.ts +102 -102
- package/lib/engine-components/ui/EventSystem.js +641 -641
- package/lib/engine-components/ui/Graphic.d.ts +45 -45
- package/lib/engine-components/ui/Graphic.js +236 -236
- package/lib/engine-components/ui/Image.d.ts +27 -27
- package/lib/engine-components/ui/Image.js +107 -107
- package/lib/engine-components/ui/InputField.d.ts +34 -34
- package/lib/engine-components/ui/InputField.js +234 -234
- package/lib/engine-components/ui/Interfaces.d.ts +38 -38
- package/lib/engine-components/ui/Interfaces.js +12 -12
- package/lib/engine-components/ui/Layout.d.ts +72 -72
- package/lib/engine-components/ui/Layout.js +318 -318
- package/lib/engine-components/ui/Outline.d.ts +7 -7
- package/lib/engine-components/ui/Outline.js +20 -20
- package/lib/engine-components/ui/PointerEvents.d.ts +64 -64
- package/lib/engine-components/ui/PointerEvents.js +68 -68
- package/lib/engine-components/ui/RaycastUtils.d.ts +11 -11
- package/lib/engine-components/ui/RaycastUtils.js +67 -67
- package/lib/engine-components/ui/Raycaster.d.ts +18 -18
- package/lib/engine-components/ui/Raycaster.js +69 -69
- package/lib/engine-components/ui/RectTransform.d.ts +61 -61
- package/lib/engine-components/ui/RectTransform.js +343 -343
- package/lib/engine-components/ui/SpatialHtml.d.ts +6 -6
- package/lib/engine-components/ui/SpatialHtml.js +57 -57
- package/lib/engine-components/ui/Text.d.ts +74 -74
- package/lib/engine-components/ui/Text.js +534 -534
- package/lib/engine-components/ui/Utils.d.ts +23 -23
- package/lib/engine-components/ui/Utils.js +90 -90
- package/lib/engine-components/ui/index.d.ts +1 -1
- package/lib/engine-components/ui/index.js +1 -1
- package/lib/engine-components/utils/LookAt.d.ts +13 -13
- package/lib/engine-components/utils/LookAt.js +59 -59
- package/lib/engine-components/utils/OpenURL.d.ts +21 -21
- package/lib/engine-components/utils/OpenURL.js +124 -124
- package/lib/engine-components/webxr/WebARCameraBackground.d.ts +19 -19
- package/lib/engine-components/webxr/WebARCameraBackground.js +193 -193
- package/lib/engine-components/webxr/WebARSessionRoot.d.ts +38 -38
- package/lib/engine-components/webxr/WebARSessionRoot.js +407 -407
- package/lib/engine-components/webxr/WebXR.d.ts +110 -110
- package/lib/engine-components/webxr/WebXR.js +672 -672
- package/lib/engine-components/webxr/WebXRAvatar.d.ts +61 -61
- package/lib/engine-components/webxr/WebXRAvatar.js +289 -289
- package/lib/engine-components/webxr/WebXRController.d.ts +154 -154
- package/lib/engine-components/webxr/WebXRController.js +1028 -1028
- package/lib/engine-components/webxr/WebXRGrabRendering.d.ts +42 -42
- package/lib/engine-components/webxr/WebXRGrabRendering.js +137 -137
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +49 -49
- package/lib/engine-components/webxr/WebXRImageTracking.js +336 -336
- package/lib/engine-components/webxr/WebXRPlaneTracking.d.ts +49 -49
- package/lib/engine-components/webxr/WebXRPlaneTracking.js +372 -372
- package/lib/engine-components/webxr/WebXRRig.d.ts +4 -4
- package/lib/engine-components/webxr/WebXRRig.js +19 -19
- package/lib/engine-components/webxr/WebXRSync.d.ts +54 -54
- package/lib/engine-components/webxr/WebXRSync.js +410 -410
- package/lib/engine-components/webxr/index.d.ts +4 -4
- package/lib/engine-components/webxr/index.js +4 -4
- package/lib/engine-components-experimental/Presentation.d.ts +6 -6
- package/lib/engine-components-experimental/Presentation.js +9 -9
- package/lib/engine-components-experimental/api.d.ts +1 -1
- package/lib/engine-components-experimental/api.js +1 -1
- package/lib/engine-components-experimental/networking/PlayerSync.d.ts +50 -50
- package/lib/engine-components-experimental/networking/PlayerSync.js +200 -200
- package/lib/engine-schemes/api.d.ts +1 -1
- package/lib/engine-schemes/api.js +1 -1
- package/lib/engine-schemes/schemes.d.ts +7 -7
- package/lib/engine-schemes/schemes.js +19 -19
- package/lib/engine-schemes/synced-camera-model.d.ts +25 -25
- package/lib/engine-schemes/synced-camera-model.js +67 -67
- package/lib/engine-schemes/synced-transform-model.d.ts +31 -31
- package/lib/engine-schemes/synced-transform-model.js +66 -66
- package/lib/engine-schemes/transform.d.ts +12 -12
- package/lib/engine-schemes/transform.js +39 -39
- package/lib/engine-schemes/vec3.d.ts +11 -11
- package/lib/engine-schemes/vec3.js +29 -29
- package/lib/engine-schemes/vec4.d.ts +12 -12
- package/lib/engine-schemes/vec4.js +33 -33
- package/lib/engine-schemes/vr-user-state-buffer.d.ts +36 -36
- package/lib/engine-schemes/vr-user-state-buffer.js +103 -103
- package/lib/include/three/ARButton.d.ts +3 -3
- package/lib/include/three/ARButton.js +151 -151
- package/lib/include/three/EXT_mesh_gpu_instancing_exporter.d.ts +6 -6
- package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js +45 -45
- package/lib/include/three/VRButton.d.ts +5 -5
- package/lib/include/three/VRButton.js +118 -118
- package/lib/needle-engine.d.ts +6 -6
- package/lib/needle-engine.js +49 -49
- package/package.json +1 -1
- package/plugins/common/config.cjs +14 -14
- package/plugins/common/config.js +19 -19
- package/plugins/common/generator.js +10 -10
- package/plugins/common/license.cjs +30 -30
- package/plugins/common/version.js +11 -11
- package/plugins/next/license.cjs +4 -4
- package/plugins/next/next.js +70 -70
- package/plugins/types/index.d.ts +1 -1
- package/plugins/types/needleConfig.d.ts +21 -21
- package/plugins/types/userconfig.d.ts +42 -42
- package/plugins/vite/alias.js +70 -70
- package/plugins/vite/build.js +19 -19
- package/plugins/vite/config.js +73 -73
- package/plugins/vite/copyfiles.js +134 -134
- package/plugins/vite/defines.js +45 -45
- package/plugins/vite/dependency-watcher.js +224 -224
- package/plugins/vite/drop-client.js +76 -76
- package/plugins/vite/drop.js +82 -82
- package/plugins/vite/editor-connection.js +121 -121
- package/plugins/vite/facebook-instant-games.js +99 -99
- package/plugins/vite/gzip.js +5 -5
- package/plugins/vite/imports-logger.js +143 -143
- package/plugins/vite/index.js +81 -81
- package/plugins/vite/license.js +42 -42
- package/plugins/vite/meta.js +149 -149
- package/plugins/vite/peer.js +31 -31
- package/plugins/vite/poster-client.js +59 -59
- package/plugins/vite/poster.js +73 -73
- package/plugins/vite/reload-client.js +15 -15
- package/plugins/vite/reload.js +363 -363
- package/plugins/vite/transform-codegen.js +55 -55
- package/plugins/vite/vite-4.4-hack.js +31 -31
- package/src/engine/api.ts +54 -54
- package/src/engine/assets/index.ts +4 -4
- package/src/engine/codegen/register_types.ts +441 -441
- package/src/engine/debug/debug.ts +29 -29
- package/src/engine/debug/debug_console.ts +213 -213
- package/src/engine/debug/debug_overlay.ts +283 -283
- package/src/engine/engine.ts +13 -13
- package/src/engine/engine_addressables.ts +494 -494
- package/src/engine/engine_application.ts +53 -53
- package/src/engine/engine_assetdatabase.ts +383 -383
- package/src/engine/engine_camera.ts +32 -32
- package/src/engine/engine_components.ts +266 -266
- package/src/engine/engine_components_internal.ts +42 -42
- package/src/engine/engine_constants.ts +42 -42
- package/src/engine/engine_context.ts +1386 -1386
- package/src/engine/engine_context_registry.ts +103 -103
- package/src/engine/engine_coroutine.ts +24 -24
- package/src/engine/engine_create_objects.ts +39 -39
- package/src/engine/engine_default_parameters.ts +3 -3
- package/src/engine/engine_editor-sync.ts +29 -29
- package/src/engine/engine_element.ts +592 -592
- package/src/engine/engine_element_attributes.ts +61 -61
- package/src/engine/engine_element_extras.ts +16 -16
- package/src/engine/engine_element_loading.ts +341 -341
- package/src/engine/engine_element_overlay.ts +160 -160
- package/src/engine/engine_fileloader.js +8 -8
- package/src/engine/engine_gameobject.ts +621 -621
- package/src/engine/engine_generic_utils.js +13 -13
- package/src/engine/engine_gizmos.ts +321 -321
- package/src/engine/engine_gltf.ts +30 -30
- package/src/engine/engine_gltf_builtin_components.ts +350 -350
- package/src/engine/engine_hot_reload.ts +196 -196
- package/src/engine/engine_input.ts +879 -879
- package/src/engine/engine_input_utils.ts +23 -23
- package/src/engine/engine_instancing.ts +42 -42
- package/src/engine/engine_license.ts +413 -413
- package/src/engine/engine_lifecycle_api.ts +29 -29
- package/src/engine/engine_lifecycle_functions_internal.ts +36 -36
- package/src/engine/engine_lightdata.ts +113 -113
- package/src/engine/engine_loaders.ts +77 -77
- package/src/engine/engine_mainloop_utils.ts +431 -431
- package/src/engine/engine_math.ts +174 -174
- package/src/engine/engine_networking.ts +742 -742
- package/src/engine/engine_networking_auto.ts +373 -373
- package/src/engine/engine_networking_files.ts +206 -206
- package/src/engine/engine_networking_files_default_components.ts +54 -54
- package/src/engine/engine_networking_instantiate.ts +362 -362
- package/src/engine/engine_networking_peer.ts +158 -158
- package/src/engine/engine_networking_streams.ts +489 -489
- package/src/engine/engine_networking_types.ts +18 -18
- package/src/engine/engine_networking_utils.ts +23 -23
- package/src/engine/engine_networking_websocket.ts +2 -2
- package/src/engine/engine_patcher.ts +199 -199
- package/src/engine/engine_physics.ts +287 -287
- package/src/engine/engine_physics.types.ts +43 -43
- package/src/engine/engine_physics_rapier.ts +1385 -1385
- package/src/engine/engine_playerview.ts +79 -79
- package/src/engine/engine_scenelighting.ts +313 -313
- package/src/engine/engine_scenetools.ts +242 -242
- package/src/engine/engine_serialization.ts +6 -6
- package/src/engine/engine_serialization_builtin_serializer.ts +415 -415
- package/src/engine/engine_serialization_core.ts +680 -680
- package/src/engine/engine_serialization_decorator.ts +68 -68
- package/src/engine/engine_setup.ts +1 -1
- package/src/engine/engine_shaders.ts +242 -242
- package/src/engine/engine_shims.ts +28 -28
- package/src/engine/engine_texture.ts +70 -70
- package/src/engine/engine_three_utils.ts +382 -382
- package/src/engine/engine_time.ts +55 -55
- package/src/engine/engine_types.ts +489 -489
- package/src/engine/engine_typestore.ts +41 -41
- package/src/engine/engine_util_decorator.ts +134 -134
- package/src/engine/engine_utils.ts +605 -605
- package/src/engine/engine_utils_screenshot.ts +84 -84
- package/src/engine/engine_web_api.ts +119 -119
- package/src/engine/extensions/EXT_texture_exr.ts +49 -49
- package/src/engine/extensions/NEEDLE_animator_controller_model.ts +193 -193
- package/src/engine/extensions/NEEDLE_components.ts +250 -250
- package/src/engine/extensions/NEEDLE_gameobject_data.ts +82 -82
- package/src/engine/extensions/NEEDLE_lighting_settings.ts +210 -210
- package/src/engine/extensions/NEEDLE_lightmaps.ts +130 -130
- package/src/engine/extensions/NEEDLE_persistent_assets.ts +75 -75
- package/src/engine/extensions/NEEDLE_progressive.ts +412 -412
- package/src/engine/extensions/NEEDLE_render_objects.ts +209 -209
- package/src/engine/extensions/NEEDLE_techniques_webgl.ts +618 -618
- package/src/engine/extensions/extension_resolver.ts +4 -4
- package/src/engine/extensions/extension_utils.ts +149 -149
- package/src/engine/extensions/extensions.ts +118 -118
- package/src/engine/extensions/index.ts +4 -4
- package/src/engine/extensions/usage_tracker.ts +95 -95
- package/src/engine/js-extensions/Camera.ts +34 -34
- package/src/engine/js-extensions/Layers.ts +19 -19
- package/src/engine/js-extensions/index.ts +1 -1
- package/src/engine/shaders/shaderData.ts +67 -67
- package/src/engine/tests/test_utils.ts +63 -63
- package/src/engine-components/AlignmentConstraint.ts +35 -35
- package/src/engine-components/Animation.ts +345 -345
- package/src/engine-components/AnimationCurve.ts +83 -83
- package/src/engine-components/AnimationUtils.ts +117 -117
- package/src/engine-components/Animator.ts +243 -243
- package/src/engine-components/AnimatorController.ts +1020 -1020
- package/src/engine-components/AudioListener.ts +32 -32
- package/src/engine-components/AudioSource.ts +419 -419
- package/src/engine-components/AvatarLoader.ts +204 -204
- package/src/engine-components/AxesHelper.ts +33 -33
- package/src/engine-components/BasicIKConstraint.ts +53 -53
- package/src/engine-components/BoxCollider.ts +1 -1
- package/src/engine-components/BoxHelperComponent.ts +100 -100
- package/src/engine-components/Camera.ts +454 -454
- package/src/engine-components/CameraUtils.ts +89 -89
- package/src/engine-components/CharacterController.ts +243 -243
- package/src/engine-components/Collider.ts +160 -160
- package/src/engine-components/Component.ts +670 -670
- package/src/engine-components/ContactShadows.ts +265 -265
- package/src/engine-components/DeleteBox.ts +35 -35
- package/src/engine-components/DeviceFlag.ts +42 -42
- package/src/engine-components/DragControls.ts +574 -574
- package/src/engine-components/DropListener.ts +112 -112
- package/src/engine-components/Duplicatable.ts +146 -146
- package/src/engine-components/EventList.ts +125 -125
- package/src/engine-components/EventTrigger.ts +47 -47
- package/src/engine-components/EventType.ts +87 -87
- package/src/engine-components/FlyControls.ts +31 -31
- package/src/engine-components/Fog.ts +59 -59
- package/src/engine-components/Gizmos.ts +52 -52
- package/src/engine-components/GridHelper.ts +40 -40
- package/src/engine-components/GroundProjection.ts +97 -97
- package/src/engine-components/Interactable.ts +18 -18
- package/src/engine-components/Joints.ts +51 -51
- package/src/engine-components/LODGroup.ts +145 -145
- package/src/engine-components/Light.ts +493 -493
- package/src/engine-components/LookAtConstraint.ts +11 -11
- package/src/engine-components/NestedGltf.ts +70 -70
- package/src/engine-components/Networking.ts +72 -72
- package/src/engine-components/OffsetConstraint.ts +59 -59
- package/src/engine-components/OrbitControls.ts +653 -653
- package/src/engine-components/ParticleSystem.ts +1192 -1192
- package/src/engine-components/ParticleSystemModules.ts +1481 -1481
- package/src/engine-components/ParticleSystemSubEmitter.ts +110 -110
- package/src/engine-components/PlayerColor.ts +93 -93
- package/src/engine-components/ReflectionProbe.ts +192 -192
- package/src/engine-components/Renderer.ts +1125 -1125
- package/src/engine-components/RendererLightmap.ts +145 -145
- package/src/engine-components/RigidBody.ts +453 -453
- package/src/engine-components/SceneSwitcher.ts +594 -594
- package/src/engine-components/ScreenCapture.ts +437 -437
- package/src/engine-components/ShadowCatcher.ts +149 -149
- package/src/engine-components/Skybox.ts +281 -281
- package/src/engine-components/SmoothFollow.ts +57 -57
- package/src/engine-components/SpatialTrigger.ts +142 -142
- package/src/engine-components/SpectatorCamera.ts +675 -675
- package/src/engine-components/SphereCollider.ts +1 -1
- package/src/engine-components/SpriteRenderer.ts +244 -244
- package/src/engine-components/SyncedCamera.ts +208 -208
- package/src/engine-components/SyncedRoom.ts +166 -166
- package/src/engine-components/SyncedTransform.ts +336 -336
- package/src/engine-components/TestRunner.ts +114 -114
- package/src/engine-components/TransformGizmo.ts +157 -157
- package/src/engine-components/VideoPlayer.ts +831 -831
- package/src/engine-components/Voip.ts +214 -214
- package/src/engine-components/XRFlag.ts +138 -138
- package/src/engine-components/api.ts +22 -22
- package/src/engine-components/avatar/AvatarBlink_Simple.ts +67 -67
- package/src/engine-components/avatar/AvatarEyeLook_Rotation.ts +68 -68
- package/src/engine-components/avatar/Avatar_Brain_LookAt.ts +136 -136
- package/src/engine-components/avatar/Avatar_MouthShapes.ts +81 -81
- package/src/engine-components/avatar/Avatar_MustacheShake.ts +28 -28
- package/src/engine-components/codegen/components.ts +216 -216
- package/src/engine-components/debug/LogStats.ts +21 -21
- package/src/engine-components/export/gltf/GltfExport.ts +231 -231
- package/src/engine-components/export/usdz/Extension.ts +11 -11
- package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1773 -1773
- package/src/engine-components/export/usdz/USDZExporter.ts +477 -477
- package/src/engine-components/export/usdz/extensions/Animation.ts +774 -774
- package/src/engine-components/export/usdz/extensions/DocumentExtension.ts +9 -9
- package/src/engine-components/export/usdz/extensions/USDZText.ts +287 -287
- package/src/engine-components/export/usdz/extensions/USDZUI.ts +119 -119
- package/src/engine-components/export/usdz/extensions/behavior/Actions.ts +98 -98
- package/src/engine-components/export/usdz/extensions/behavior/AudioExtension.ts +67 -67
- package/src/engine-components/export/usdz/extensions/behavior/Behaviour.ts +202 -202
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +963 -963
- package/src/engine-components/export/usdz/extensions/behavior/BehavioursBuilder.ts +517 -517
- package/src/engine-components/export/usdz/index.ts +2 -2
- package/src/engine-components/export/usdz/utils/animationutils.ts +100 -100
- package/src/engine-components/export/usdz/utils/quicklook.ts +42 -42
- package/src/engine-components/export/usdz/utils/timeutils.ts +19 -19
- package/src/engine-components/js-extensions/ExtensionUtils.ts +81 -81
- package/src/engine-components/js-extensions/Object3D.ts +181 -181
- package/src/engine-components/js-extensions/RGBAColor.ts +54 -54
- package/src/engine-components/js-extensions/Vector.ts +16 -16
- package/src/engine-components/js-extensions/index.ts +2 -2
- package/src/engine-components/postprocessing/Effects/Antialiasing.ts +51 -51
- package/src/engine-components/postprocessing/Effects/Bloom.ts +76 -76
- package/src/engine-components/postprocessing/Effects/ChromaticAberration.ts +35 -35
- package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +96 -96
- package/src/engine-components/postprocessing/Effects/DepthOfField.ts +93 -93
- package/src/engine-components/postprocessing/Effects/Pixelation.ts +26 -26
- package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +84 -84
- package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +98 -98
- package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +55 -55
- package/src/engine-components/postprocessing/Effects/Tonemapping.ts +54 -54
- package/src/engine-components/postprocessing/Effects/Vignette.ts +54 -54
- package/src/engine-components/postprocessing/PostProcessingEffect.ts +148 -148
- package/src/engine-components/postprocessing/PostProcessingHandler.ts +232 -232
- package/src/engine-components/postprocessing/Volume.ts +216 -216
- package/src/engine-components/postprocessing/VolumeParameter.ts +92 -92
- package/src/engine-components/postprocessing/VolumeProfile.ts +40 -40
- package/src/engine-components/postprocessing/index.ts +3 -3
- package/src/engine-components/timeline/PlayableDirector.ts +666 -666
- package/src/engine-components/timeline/SignalAsset.ts +138 -138
- package/src/engine-components/timeline/TimelineModels.ts +93 -93
- package/src/engine-components/timeline/TimelineTracks.ts +906 -906
- package/src/engine-components/timeline/index.ts +3 -3
- package/src/engine-components/ui/BaseUIComponent.ts +195 -195
- package/src/engine-components/ui/Button.ts +283 -283
- package/src/engine-components/ui/Canvas.ts +390 -390
- package/src/engine-components/ui/CanvasGroup.ts +49 -49
- package/src/engine-components/ui/EventSystem.ts +736 -736
- package/src/engine-components/ui/Graphic.ts +255 -255
- package/src/engine-components/ui/Image.ts +102 -102
- package/src/engine-components/ui/InputField.ts +290 -290
- package/src/engine-components/ui/Interfaces.ts +57 -57
- package/src/engine-components/ui/Layout.ts +322 -322
- package/src/engine-components/ui/Outline.ts +12 -12
- package/src/engine-components/ui/PointerEvents.ts +118 -118
- package/src/engine-components/ui/RaycastUtils.ts +68 -68
- package/src/engine-components/ui/Raycaster.ts +73 -73
- package/src/engine-components/ui/RectTransform.ts +364 -364
- package/src/engine-components/ui/SpatialHtml.ts +63 -63
- package/src/engine-components/ui/Text.ts +572 -572
- package/src/engine-components/ui/Utils.ts +110 -110
- package/src/engine-components/utils/LookAt.ts +65 -65
- package/src/engine-components/utils/OpenURL.ts +118 -118
- package/src/engine-components/webxr/WebARCameraBackground.ts +224 -224
- package/src/engine-components/webxr/WebARSessionRoot.ts +446 -446
- package/src/engine-components/webxr/WebXR.ts +761 -761
- package/src/engine-components/webxr/WebXRAvatar.ts +356 -356
- package/src/engine-components/webxr/WebXRController.ts +1168 -1168
- package/src/engine-components/webxr/WebXRGrabRendering.ts +150 -150
- package/src/engine-components/webxr/WebXRImageTracking.ts +371 -371
- package/src/engine-components/webxr/WebXRPlaneTracking.ts +429 -429
- package/src/engine-components/webxr/WebXRRig.ts +21 -21
- package/src/engine-components/webxr/WebXRSync.ts +463 -463
- package/src/engine-components/webxr/index.ts +3 -3
- package/src/engine-components-experimental/Presentation.ts +12 -12
- package/src/engine-components-experimental/networking/PlayerSync.ts +217 -217
- package/src/engine-schemes/COMPILE_SCHEMES.bat +3 -3
- package/src/engine-schemes/COMPILE_TS.bat +11 -11
- package/src/engine-schemes/schemes.ts +27 -27
- package/src/engine-schemes/synced-camera-model.ts +92 -92
- package/src/engine-schemes/synced-transform-model.ts +90 -90
- package/src/engine-schemes/syncedCamera.fbs +10 -10
- package/src/engine-schemes/transform.ts +50 -50
- package/src/engine-schemes/transforms.fbs +25 -25
- package/src/engine-schemes/vec.fbs +19 -19
- package/src/engine-schemes/vec2.ts +33 -33
- package/src/engine-schemes/vec3.ts +38 -38
- package/src/engine-schemes/vec4.ts +43 -43
- package/src/engine-schemes/vr-user-state-buffer.ts +138 -138
- package/src/engine-schemes/vrUserStateBuffer.fbs +16 -16
- package/src/include/draco/draco_decoder.js +34 -34
- package/src/include/draco/draco_wasm_wrapper.js +117 -117
- package/src/include/ktx2/basis_transcoder.js +21 -21
- package/src/include/needle/arial-msdf.json +1471 -1471
- package/src/include/three/ARButton.js +231 -231
- package/src/include/three/DragControls.js +231 -231
- package/src/include/three/EXT_mesh_gpu_instancing_exporter.js +66 -66
- package/src/include/three/VRButton.js +194 -194
- package/src/needle-engine.ts +55 -55
- package/src/engine/dist/api.js +0 -73
- package/src/engine/dist/api.js.meta +0 -7
- package/src/engine/dist/engine_networking_streams.js +0 -474
- package/src/engine/dist/engine_networking_streams.js.meta +0 -7
- package/src/engine-schemes/dist/api.js +0 -17
- package/src/engine-schemes/dist/api.js.meta +0 -7
- package/src/engine-schemes/dist/schemes.js +0 -25
- package/src/engine-schemes/dist/schemes.js.meta +0 -7
- package/src/engine-schemes/dist/synced-camera-model.js +0 -74
- package/src/engine-schemes/dist/synced-camera-model.js.meta +0 -7
- package/src/engine-schemes/dist/synced-transform-model.js +0 -73
- package/src/engine-schemes/dist/synced-transform-model.js.meta +0 -7
- package/src/engine-schemes/dist/transform.js +0 -46
- package/src/engine-schemes/dist/transform.js.meta +0 -7
- package/src/engine-schemes/dist/vec2.js +0 -32
- package/src/engine-schemes/dist/vec2.js.meta +0 -7
- package/src/engine-schemes/dist/vec3.js +0 -36
- package/src/engine-schemes/dist/vec3.js.meta +0 -7
- package/src/engine-schemes/dist/vec4.js +0 -40
- package/src/engine-schemes/dist/vec4.js.meta +0 -7
- package/src/engine-schemes/dist/vr-user-state-buffer.js +0 -110
- package/src/engine-schemes/dist/vr-user-state-buffer.js.meta +0 -7
- package/src/engine-schemes/flatc.exe +0 -0
|
@@ -1,1021 +1,1021 @@
|
|
|
1
|
-
import { Animator } from "./Animator.js";
|
|
2
|
-
import type { AnimatorControllerModel, Condition, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
3
|
-
import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
4
|
-
import { AnimationAction, AnimationClip, AnimationMixer, AxesHelper, Euler, KeyframeTrack, LoopOnce, Object3D, Quaternion, Vector3 } from "three";
|
|
5
|
-
import { deepClone, getParam } from "../engine/engine_utils.js";
|
|
6
|
-
import { Context } from "../engine/engine_setup.js";
|
|
7
|
-
import { TypeStore } from "../engine/engine_typestore.js";
|
|
8
|
-
import { SerializationContext, TypeSerializer, assign } from "../engine/engine_serialization_core.js";
|
|
9
|
-
import { Mathf } from "../engine/engine_math.js";
|
|
10
|
-
import { isAnimationAction } from "../engine/engine_three_utils.js";
|
|
11
|
-
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
12
|
-
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
13
|
-
|
|
14
|
-
const debug = getParam("debuganimatorcontroller");
|
|
15
|
-
const debugRootMotion = getParam("debugrootmotion");
|
|
16
|
-
|
|
17
|
-
function stringToHash(str): number {
|
|
18
|
-
let hash = 0;
|
|
19
|
-
for (let i = 0; i < str.length; i++) {
|
|
20
|
-
const char = str.charCodeAt(i);
|
|
21
|
-
hash = ((hash << 5) - hash) + char;
|
|
22
|
-
hash = hash & hash;
|
|
23
|
-
}
|
|
24
|
-
return hash;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
declare type CreateAnimatorControllerOptions = {
|
|
28
|
-
/** Should each animationstate loop */
|
|
29
|
-
looping?: boolean,
|
|
30
|
-
/** Set to false to disable generating transitions between animationclips */
|
|
31
|
-
autoTransition?: boolean,
|
|
32
|
-
/** Set to a positive value in seconds for transition duration between states */
|
|
33
|
-
transitionDuration?: number,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class AnimatorController {
|
|
37
|
-
|
|
38
|
-
/** Create an animatorcontroller with clips assigned */
|
|
39
|
-
static createFromClips(clips: AnimationClip[], options: CreateAnimatorControllerOptions = { looping: false, autoTransition: true, transitionDuration: 0 }): AnimatorController {
|
|
40
|
-
const states: State[] = [];
|
|
41
|
-
for (let i = 0; i < clips.length; i++) {
|
|
42
|
-
const clip = clips[i];
|
|
43
|
-
const transitions: Transition[] = [];
|
|
44
|
-
|
|
45
|
-
if (options.autoTransition !== false) {
|
|
46
|
-
const dur = options.transitionDuration ?? 0;
|
|
47
|
-
const normalizedDuration = dur / clip.duration;
|
|
48
|
-
// automatically transition to self by default
|
|
49
|
-
let nextState = i;
|
|
50
|
-
if (options.autoTransition === undefined || options.autoTransition === true) {
|
|
51
|
-
nextState = (i + 1) % clips.length;
|
|
52
|
-
}
|
|
53
|
-
transitions.push({
|
|
54
|
-
exitTime: 1 - normalizedDuration,
|
|
55
|
-
offset: 0,
|
|
56
|
-
duration: dur,
|
|
57
|
-
hasExitTime: true,
|
|
58
|
-
destinationState: nextState,
|
|
59
|
-
conditions: [],
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const state: State = {
|
|
64
|
-
name: clip.name,
|
|
65
|
-
hash: i, // by using the index it's easy for users to call play(2) to play the clip at index 2
|
|
66
|
-
motion: {
|
|
67
|
-
name: clip.name,
|
|
68
|
-
clip: clip,
|
|
69
|
-
isLooping: options?.looping ?? false,
|
|
70
|
-
},
|
|
71
|
-
transitions: transitions,
|
|
72
|
-
behaviours: []
|
|
73
|
-
}
|
|
74
|
-
states.push(state);
|
|
75
|
-
}
|
|
76
|
-
const model: AnimatorControllerModel = {
|
|
77
|
-
name: "AnimatorController",
|
|
78
|
-
guid: new InstantiateIdProvider(Date.now()).generateUUID(),
|
|
79
|
-
parameters: [],
|
|
80
|
-
layers: [{
|
|
81
|
-
name: "Base Layer",
|
|
82
|
-
stateMachine: {
|
|
83
|
-
defaultState: 0,
|
|
84
|
-
states: states
|
|
85
|
-
}
|
|
86
|
-
}]
|
|
87
|
-
}
|
|
88
|
-
const controller = new AnimatorController(model);
|
|
89
|
-
return controller;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
play(name: string | number, layerIndex: number = -1, normalizedTime: number = Number.NEGATIVE_INFINITY, durationInSec: number = 0) {
|
|
93
|
-
if (layerIndex < 0) layerIndex = 0;
|
|
94
|
-
else if (layerIndex >= this.model.layers.length) {
|
|
95
|
-
console.warn("invalid layer");
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const layer = this.model.layers[layerIndex];
|
|
99
|
-
const sm = layer.stateMachine;
|
|
100
|
-
for (const state of sm.states) {
|
|
101
|
-
if (state.name === name || state.hash === name) {
|
|
102
|
-
if (debug)
|
|
103
|
-
console.log("transition to ", state);
|
|
104
|
-
this.transitionTo(state, durationInSec, normalizedTime);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
console.warn("Could not find " + name + " to play");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
reset() {
|
|
112
|
-
this.setStartTransition();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
setBool(name: string | number, value: boolean) {
|
|
116
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
117
|
-
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = value);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
getBool(name: string | number): boolean {
|
|
121
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
122
|
-
return this.model?.parameters?.find(p => p[key] === name)?.value as boolean ?? false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
setFloat(name: string | number, val: number) {
|
|
126
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
127
|
-
const filtered = this.model?.parameters?.filter(p => p[key] === name);
|
|
128
|
-
filtered.forEach(p => p.value = val);
|
|
129
|
-
return filtered?.length > 0;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
getFloat(name: string | number): number {
|
|
133
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
134
|
-
return this.model?.parameters?.find(p => p[key] === name)?.value as number ?? 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
setInteger(name: string | number, val: number) {
|
|
138
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
139
|
-
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = val);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
getInteger(name: string | number): number {
|
|
143
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
144
|
-
return this.model?.parameters?.find(p => p[key] === name)?.value as number ?? 0;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
setTrigger(name: string | number) {
|
|
148
|
-
if (debug)
|
|
149
|
-
console.log("SET TRIGGER", name);
|
|
150
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
151
|
-
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = true);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
resetTrigger(name: string | number) {
|
|
155
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
156
|
-
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = false);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
getTrigger(name: string | number): boolean {
|
|
160
|
-
const key = typeof name === "string" ? "name" : "hash";
|
|
161
|
-
return this.model?.parameters?.find(p => p[key] === name)?.value as boolean ?? false;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
isInTransition(): boolean {
|
|
165
|
-
return this._activeStates.length > 1;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
setSpeed(speed: number) {
|
|
169
|
-
this._speed = speed;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**@deprecated use findState */
|
|
173
|
-
FindState(name: string | number | undefined | null): State | null { return this.findState(name); }
|
|
174
|
-
findState(name: string | number | undefined | null): State | null {
|
|
175
|
-
if (!name) return null;
|
|
176
|
-
if (Array.isArray(this.model.layers)) {
|
|
177
|
-
for (const layer of this.model.layers) {
|
|
178
|
-
for (const state of layer.stateMachine.states) {
|
|
179
|
-
if (state.name === name || state.hash == name) return state;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
normalizedStartOffset: number = 0;
|
|
187
|
-
|
|
188
|
-
private _speed: number = 1;
|
|
189
|
-
|
|
190
|
-
animator?: Animator;
|
|
191
|
-
model: AnimatorControllerModel;
|
|
192
|
-
get context(): Context | undefined | null { return this.animator?.context; }
|
|
193
|
-
get mixer() {
|
|
194
|
-
return this._mixer;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// applyRootMotion(obj: Object3D) {
|
|
198
|
-
// // this.internalApplyRootMotion(obj);
|
|
199
|
-
// }
|
|
200
|
-
|
|
201
|
-
bind(animator: Animator) {
|
|
202
|
-
if (!animator) console.error("AnimatorController.bind: animator is null");
|
|
203
|
-
else if (this.animator !== animator) {
|
|
204
|
-
this.animator = animator;
|
|
205
|
-
this._mixer = new AnimationMixer(this.animator.gameObject);
|
|
206
|
-
this.createActions(this.animator);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
clone() {
|
|
211
|
-
if (typeof this.model === "string") {
|
|
212
|
-
console.warn("AnimatorController has not been resolved, can not create model from string", this.model);
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
// clone runtime controller but dont clone clip or action
|
|
216
|
-
const clonedModel = deepClone(this.model, (_owner, _key, _value) => {
|
|
217
|
-
if (_value === null || _value === undefined) return true;
|
|
218
|
-
// dont clone three Objects
|
|
219
|
-
if (_value.type === "Object3D" || _value.isObject3D === true) return false;
|
|
220
|
-
// dont clone AnimationAction
|
|
221
|
-
if (isAnimationAction(_value)) { //.constructor.name === "AnimationAction") {
|
|
222
|
-
// console.log(_value);
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
// dont clone AnimationClip
|
|
226
|
-
if (_value["tracks"] !== undefined) return false;
|
|
227
|
-
return true;
|
|
228
|
-
}) as AnimatorControllerModel;
|
|
229
|
-
console.assert(clonedModel !== this.model);
|
|
230
|
-
const controller = new AnimatorController(clonedModel);
|
|
231
|
-
return controller;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
update(weight: number) {
|
|
235
|
-
if (!this.animator) return;
|
|
236
|
-
this.evaluateTransitions();
|
|
237
|
-
this.updateActiveStates(weight);
|
|
238
|
-
// We want to update the animation mixer even if there is no active state (e.g. in cases where an empty animator controller is assigned and the timeline runs)
|
|
239
|
-
// if (!this._activeState) return;
|
|
240
|
-
const dt = this.animator.context.time.deltaTime;
|
|
241
|
-
if (this.animator.applyRootMotion) {
|
|
242
|
-
this.rootMotionHandler?.onBeforeUpdate(weight);
|
|
243
|
-
}
|
|
244
|
-
this._mixer.update(dt);
|
|
245
|
-
if (this.animator.applyRootMotion) {
|
|
246
|
-
this.rootMotionHandler?.onAfterUpdate(weight);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
private _mixer!: AnimationMixer;
|
|
252
|
-
private _activeState?: State;
|
|
253
|
-
get activeState(): State | undefined { return this._activeState; }
|
|
254
|
-
|
|
255
|
-
constructor(model: AnimatorControllerModel) {
|
|
256
|
-
this.model = model;
|
|
257
|
-
if (debug) console.log(this);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
private _activeStates: State[] = [];
|
|
261
|
-
|
|
262
|
-
private updateActiveStates(weight: number) {
|
|
263
|
-
for (let i = 0; i < this._activeStates.length; i++) {
|
|
264
|
-
const state = this._activeStates[i];
|
|
265
|
-
const motion = state.motion;
|
|
266
|
-
if (!motion.action) {
|
|
267
|
-
this._activeStates.splice(i, 1);
|
|
268
|
-
i--;
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
const action = motion.action;
|
|
272
|
-
action.weight = weight;
|
|
273
|
-
// console.log(action.getClip().name, action.getEffectiveWeight(), action.isScheduled());
|
|
274
|
-
if ((action.getEffectiveWeight() <= 0 && !action.isRunning())) {
|
|
275
|
-
if (debug)
|
|
276
|
-
console.debug("REMOVE", state.name, action.getEffectiveWeight(), action.isRunning(), action.isScheduled())
|
|
277
|
-
this._activeStates.splice(i, 1);
|
|
278
|
-
i--;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
private setStartTransition() {
|
|
285
|
-
for (const layer of this.model.layers) {
|
|
286
|
-
const sm = layer.stateMachine;
|
|
287
|
-
if (sm.defaultState === undefined) {
|
|
288
|
-
if (debug)
|
|
289
|
-
console.warn("AnimatorController default state is undefined, will assign state 0 as default", layer);
|
|
290
|
-
sm.defaultState = 0;
|
|
291
|
-
}
|
|
292
|
-
const start = sm.states[sm.defaultState];
|
|
293
|
-
this.transitionTo(start, 0, this.normalizedStartOffset);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private evaluateTransitions() {
|
|
298
|
-
let didEnterStateThisFrame = false;
|
|
299
|
-
if (!this._activeState) {
|
|
300
|
-
this.setStartTransition();
|
|
301
|
-
if (!this._activeState) return;
|
|
302
|
-
didEnterStateThisFrame = true;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const state = this._activeState;
|
|
306
|
-
const action = state.motion.action;
|
|
307
|
-
let index = 0;
|
|
308
|
-
for (const transition of state.transitions) {
|
|
309
|
-
++index;
|
|
310
|
-
// transition without exit time and without condition that transition to itself are ignored
|
|
311
|
-
if (!transition.hasExitTime && transition.conditions.length <= 0) {
|
|
312
|
-
// if (this._activeState && this.getState(transition.destinationState, currentLayer)?.hash === this._activeState.hash)
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
let allConditionsAreMet = true;
|
|
317
|
-
for (const cond of transition.conditions) {
|
|
318
|
-
if (!this.evaluateCondition(cond)) {
|
|
319
|
-
allConditionsAreMet = false;
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (!allConditionsAreMet) continue;
|
|
324
|
-
|
|
325
|
-
if (debug && allConditionsAreMet) {
|
|
326
|
-
// console.log("All conditions are met", transition);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
if (action) {
|
|
330
|
-
const dur = state.motion.clip!.duration;
|
|
331
|
-
const normalizedTime = dur <= 0 ? 1 : Math.abs(action.time / dur);
|
|
332
|
-
let makeTransition = false;
|
|
333
|
-
if (transition.hasExitTime) {
|
|
334
|
-
if (action.timeScale > 0) makeTransition = normalizedTime >= transition.exitTime;
|
|
335
|
-
// When the animation is playing backwards we need to check exit time inverted
|
|
336
|
-
else if(action.timeScale < 0) makeTransition = 1 - normalizedTime >= transition.exitTime;
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
makeTransition = true;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (makeTransition) {
|
|
343
|
-
// disable triggers for this transition
|
|
344
|
-
for (const cond of transition.conditions) {
|
|
345
|
-
const param = this.model.parameters.find(p => p.name === cond.parameter);
|
|
346
|
-
if (param?.type === AnimatorControllerParameterType.Trigger && param.value) {
|
|
347
|
-
param.value = false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// if (transition.hasExitTime && transition.exitTime >= .9999)
|
|
352
|
-
action.clampWhenFinished = true;
|
|
353
|
-
// else action.clampWhenFinished = false;
|
|
354
|
-
if (debug) {
|
|
355
|
-
console.log("transition to " + transition.destinationState, transition, normalizedTime, transition.exitTime, transition.hasExitTime);
|
|
356
|
-
// console.log(action.time, transition.exitTime);
|
|
357
|
-
}
|
|
358
|
-
this.transitionTo(transition.destinationState, transition.duration, transition.offset);
|
|
359
|
-
// use the first transition that matches all conditions and make the transition as soon as in range
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
else {
|
|
364
|
-
this.transitionTo(transition.destinationState, transition.duration, transition.offset);
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
// if none of the transitions can be made continue searching for another transition meeting the conditions
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// action.time += this.context.time.deltaTime
|
|
371
|
-
// console.log(action?.time, action?.getEffectiveWeight())
|
|
372
|
-
|
|
373
|
-
// update timescale
|
|
374
|
-
if (action) {
|
|
375
|
-
let speedFactor = state.speed ?? 1;
|
|
376
|
-
if (state.speedParameter)
|
|
377
|
-
speedFactor *= this.getFloat(state.speedParameter);
|
|
378
|
-
if (speedFactor !== undefined) {
|
|
379
|
-
action.timeScale = speedFactor * this._speed;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
let didTriggerLooping = false;
|
|
384
|
-
if (state.motion.isLooping && action) {
|
|
385
|
-
// we dont use the three loop state here because it prevents the transition check above
|
|
386
|
-
// it is easier if we re-trigger loop here.
|
|
387
|
-
// We also can easily add the cycle offset settings from unity later
|
|
388
|
-
if (action.time >= action.getClip().duration) {
|
|
389
|
-
didTriggerLooping = true;
|
|
390
|
-
action.reset();
|
|
391
|
-
action.time = 0;
|
|
392
|
-
action.play();
|
|
393
|
-
}
|
|
394
|
-
else if (action.time <= 0 && action.timeScale < 0) {
|
|
395
|
-
didTriggerLooping = true;
|
|
396
|
-
action.reset();
|
|
397
|
-
action.time = action.getClip().duration;
|
|
398
|
-
action.play();
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// call update state behaviours:
|
|
403
|
-
if (!didTriggerLooping && state && !didEnterStateThisFrame && action && this.animator) {
|
|
404
|
-
if (state.behaviours) {
|
|
405
|
-
const duration = action?.getClip().duration;
|
|
406
|
-
const normalizedTime = action.time / duration;
|
|
407
|
-
const info = new AnimatorStateInfo(this._activeState, normalizedTime, duration, this._speed)
|
|
408
|
-
for (const beh of state.behaviours) {
|
|
409
|
-
if (beh.instance) {
|
|
410
|
-
beh.instance.onStateUpdate?.call(beh.instance, this.animator, info, 0);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
private getState(state: State | number, layerIndex: number): State | null {
|
|
419
|
-
if (typeof state === "number") {
|
|
420
|
-
if (state == -1) {
|
|
421
|
-
state = this.model.layers[layerIndex].stateMachine.defaultState; // exit state -> entry state
|
|
422
|
-
if (state === undefined) {
|
|
423
|
-
if (debug)
|
|
424
|
-
console.warn("AnimatorController default state is undefined: ", this.model, "Layer: " + layerIndex);
|
|
425
|
-
state = 0;
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
state = this.model.layers[layerIndex].stateMachine.states[state];
|
|
429
|
-
}
|
|
430
|
-
return state;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
private transitionTo(state: State | number, durationInSec: number, offsetNormalized: number) {
|
|
434
|
-
|
|
435
|
-
if (!this.animator) return;
|
|
436
|
-
|
|
437
|
-
const layerIndex = 0;
|
|
438
|
-
|
|
439
|
-
state = this.getState(state, layerIndex) as State;
|
|
440
|
-
|
|
441
|
-
if (!state?.motion || !state.motion.clip || !(state.motion.clip instanceof AnimationClip)) {
|
|
442
|
-
// if(debug) console.warn("State has no clip or motion", state);
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const isSelf = this._activeState === state;
|
|
447
|
-
if (isSelf) {
|
|
448
|
-
const motion = state.motion;
|
|
449
|
-
if (!motion.action_loopback && motion.clip) {
|
|
450
|
-
// uncache action immediately resets the applied animation which breaks the root motion
|
|
451
|
-
// this happens if we have a transition to self and the clip is not cached yet
|
|
452
|
-
const previousMatrix = this.rootMotionHandler ? this.animator.gameObject.matrix.clone() : null;
|
|
453
|
-
this._mixer.uncacheAction(motion.clip, this.animator.gameObject);
|
|
454
|
-
if (previousMatrix)
|
|
455
|
-
previousMatrix.decompose(this.animator.gameObject.position, this.animator.gameObject.quaternion, this.animator.gameObject.scale);
|
|
456
|
-
motion.action_loopback = this.createAction(motion.clip);
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// call exit state behaviours
|
|
461
|
-
if (this._activeState?.behaviours && this._activeState.motion.action) {
|
|
462
|
-
const duration = this._activeState?.motion.clip!.duration;
|
|
463
|
-
const normalizedTime = this._activeState.motion.action.time / duration;
|
|
464
|
-
const info = new AnimatorStateInfo(this._activeState, normalizedTime, duration, this._speed);
|
|
465
|
-
for (const beh of this._activeState.behaviours) {
|
|
466
|
-
beh.instance?.onStateExit?.call(beh.instance, this.animator, info, layerIndex);
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const prevAction = this._activeState?.motion.action;
|
|
471
|
-
if (prevAction) {
|
|
472
|
-
prevAction!.fadeOut(durationInSec);
|
|
473
|
-
}
|
|
474
|
-
if (isSelf) {
|
|
475
|
-
state.motion.action = state.motion.action_loopback;
|
|
476
|
-
state.motion.action_loopback = prevAction;
|
|
477
|
-
}
|
|
478
|
-
const prev = this._activeState;
|
|
479
|
-
this._activeState = state;
|
|
480
|
-
|
|
481
|
-
const action = state.motion?.action;
|
|
482
|
-
if (action) {
|
|
483
|
-
|
|
484
|
-
offsetNormalized = Math.max(0, Math.min(1, offsetNormalized));
|
|
485
|
-
if (state.cycleOffsetParameter) {
|
|
486
|
-
let val = this.getFloat(state.cycleOffsetParameter);
|
|
487
|
-
if (typeof val === "number") {
|
|
488
|
-
if (val < 0) val += 1;
|
|
489
|
-
offsetNormalized += val;
|
|
490
|
-
offsetNormalized %= 1;
|
|
491
|
-
}
|
|
492
|
-
else if (debug) console.warn("AnimatorController cycle offset parameter is not a number", state.cycleOffsetParameter);
|
|
493
|
-
}
|
|
494
|
-
else if (typeof state.cycleOffset === "number") {
|
|
495
|
-
offsetNormalized += state.cycleOffset
|
|
496
|
-
offsetNormalized %= 1;
|
|
497
|
-
}
|
|
498
|
-
if (action.isRunning())
|
|
499
|
-
action.stop();
|
|
500
|
-
action.reset();
|
|
501
|
-
action.enabled = true;
|
|
502
|
-
const duration = state.motion.clip!.duration;
|
|
503
|
-
// if we are looping to the same state we don't want to offset the current start time
|
|
504
|
-
action.time = isSelf ? 0 : offsetNormalized * duration;
|
|
505
|
-
if (action.timeScale < 0) action.time = duration - action.time;
|
|
506
|
-
action.clampWhenFinished = true;
|
|
507
|
-
action.setLoop(LoopOnce, 0);
|
|
508
|
-
if (durationInSec > 0)
|
|
509
|
-
action.fadeIn(durationInSec);
|
|
510
|
-
else action.weight = 1;
|
|
511
|
-
action.play();
|
|
512
|
-
|
|
513
|
-
if (this.rootMotionHandler) {
|
|
514
|
-
this.rootMotionHandler.onStart(action);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if (!this._activeStates.includes(state))
|
|
518
|
-
this._activeStates.push(state);
|
|
519
|
-
|
|
520
|
-
// call enter state behaviours
|
|
521
|
-
if (this._activeState.behaviours) {
|
|
522
|
-
const info = new AnimatorStateInfo(state, offsetNormalized, duration, this._speed);
|
|
523
|
-
for (const beh of this._activeState.behaviours) {
|
|
524
|
-
beh.instance?.onStateEnter?.call(beh.instance, this.animator, info, layerIndex);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
else if (debug) {
|
|
529
|
-
if (!state["__warned_no_motion"]) {
|
|
530
|
-
state["__warned_no_motion"] = true;
|
|
531
|
-
console.warn("No action", state.motion, this);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
if (debug)
|
|
536
|
-
console.log("TRANSITION FROM " + prev?.name + " TO " + state.name, durationInSec, prevAction, action, action?.getEffectiveTimeScale(), action?.getEffectiveWeight(), action?.isRunning(), action?.isScheduled(), action?.paused);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
private createAction(clip: AnimationClip) {
|
|
540
|
-
|
|
541
|
-
// uncache clip causes issues when multiple states use the same clip
|
|
542
|
-
// this._mixer.uncacheClip(clip);
|
|
543
|
-
// instead only uncache the action when one already exists to make sure
|
|
544
|
-
// we get unique actions per state
|
|
545
|
-
const existing = this._mixer.existingAction(clip);
|
|
546
|
-
if (existing) this._mixer.uncacheAction(clip, this.animator?.gameObject);
|
|
547
|
-
|
|
548
|
-
if (this.animator?.applyRootMotion) {
|
|
549
|
-
if (!this.rootMotionHandler) {
|
|
550
|
-
this.rootMotionHandler = new RootMotionHandler(this);
|
|
551
|
-
}
|
|
552
|
-
// TODO: find root bone properly
|
|
553
|
-
const root = this.animator.gameObject;
|
|
554
|
-
return this.rootMotionHandler.createClip(this._mixer, root, clip);
|
|
555
|
-
}
|
|
556
|
-
else {
|
|
557
|
-
const action = this._mixer.clipAction(clip);
|
|
558
|
-
return action;
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
private evaluateCondition(cond: Condition): boolean {
|
|
563
|
-
const param = this.model.parameters.find(p => p.name === cond.parameter);
|
|
564
|
-
if (!param) return false;
|
|
565
|
-
// console.log(param.name
|
|
566
|
-
switch (cond.mode) {
|
|
567
|
-
case AnimatorConditionMode.If:
|
|
568
|
-
return param.value ===
|
|
569
|
-
case AnimatorConditionMode.IfNot:
|
|
570
|
-
return param.value ===
|
|
571
|
-
case AnimatorConditionMode.Greater:
|
|
572
|
-
return param.value as number > cond.threshold;
|
|
573
|
-
case AnimatorConditionMode.Less:
|
|
574
|
-
return param.value as number < cond.threshold;
|
|
575
|
-
case AnimatorConditionMode.Equals:
|
|
576
|
-
return param.value === cond.threshold;
|
|
577
|
-
case AnimatorConditionMode.NotEqual:
|
|
578
|
-
return param.value !== cond.threshold;
|
|
579
|
-
}
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
private createActions(_animator: Animator) {
|
|
584
|
-
// console.trace(this.model, _animator);
|
|
585
|
-
for (const layer of this.model.layers) {
|
|
586
|
-
const sm = layer.stateMachine;
|
|
587
|
-
for (let index = 0; index < sm.states.length; index++) {
|
|
588
|
-
const state = sm.states[index];
|
|
589
|
-
|
|
590
|
-
// ensure we have a transitions array
|
|
591
|
-
if (!state.transitions) {
|
|
592
|
-
state.transitions = [];
|
|
593
|
-
}
|
|
594
|
-
for (const t of state.transitions) {
|
|
595
|
-
// can happen if conditions are empty in blender - the exporter seems to skip empty arrays
|
|
596
|
-
if (!t.conditions) t.conditions = [];
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// ensure we have a motion even if none was exported
|
|
600
|
-
if (!state.motion) {
|
|
601
|
-
state.motion = createMotion(state.name);
|
|
602
|
-
// console.warn("Missing motion", "AnimatorController: " + this.model.name, state);
|
|
603
|
-
// sm.states.splice(index, 1);
|
|
604
|
-
// index -= 1;
|
|
605
|
-
// continue;
|
|
606
|
-
}
|
|
607
|
-
// the clips array contains which animator has which animationclip
|
|
608
|
-
if (this.animator && state.motion.clips) {
|
|
609
|
-
// TODO: we have to compare by name because on instantiate we clone objects but not the node object
|
|
610
|
-
const mapping = state.motion.clips?.find(e => e.node.name === this.animator?.gameObject?.name);
|
|
611
|
-
// console.log(state.name, mapping?.clip);
|
|
612
|
-
state.motion.clip = mapping?.clip;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// ensure we have a clip to blend to
|
|
616
|
-
if (!state.motion.clip) {
|
|
617
|
-
const clip = new AnimationClip(undefined, undefined, []);
|
|
618
|
-
state.motion.clip = clip;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
if (state.motion?.clip) {
|
|
622
|
-
const clip = state.motion.clip;
|
|
623
|
-
if (clip instanceof AnimationClip) {
|
|
624
|
-
const action = this.createAction(clip);
|
|
625
|
-
state.motion.action = action;
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
if(debug || isDevEnvironment()) console.warn("No valid animationclip assigned", state);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
// create state machine behaviours
|
|
633
|
-
if (state.behaviours && Array.isArray(state.behaviours)) {
|
|
634
|
-
for (const behaviour of state.behaviours) {
|
|
635
|
-
if (!behaviour?.typeName) continue;
|
|
636
|
-
const type = TypeStore.get(behaviour.typeName);
|
|
637
|
-
const instance: StateMachineBehaviour = new type() as StateMachineBehaviour;
|
|
638
|
-
if (instance.isStateMachineBehaviour) {
|
|
639
|
-
instance._context = this.context ?? undefined;
|
|
640
|
-
assign(instance, behaviour.properties);
|
|
641
|
-
behaviour.instance = instance;
|
|
642
|
-
}
|
|
643
|
-
if (debug) console.log("Created animator controller behaviour", state.name, behaviour.typeName, behaviour.properties, instance);
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
*enumerateActions() {
|
|
651
|
-
if (!this.model.layers) return;
|
|
652
|
-
for (const layer of this.model.layers) {
|
|
653
|
-
const sm = layer.stateMachine;
|
|
654
|
-
for (let index = 0; index < sm.states.length; index++) {
|
|
655
|
-
const state = sm.states[index];
|
|
656
|
-
if (state?.motion) {
|
|
657
|
-
if (state.motion.action)
|
|
658
|
-
yield state.motion.action;
|
|
659
|
-
if (state.motion.action_loopback)
|
|
660
|
-
yield state.motion.action_loopback;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
// https://docs.unity3d.com/Manual/RootMotion.html
|
|
668
|
-
private rootMotionHandler?: RootMotionHandler;
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
// private findRootBone(obj: Object3D): Object3D | null {
|
|
672
|
-
// if (this.animationRoot) return this.animationRoot;
|
|
673
|
-
// if (obj.type === "Bone") {
|
|
674
|
-
// this.animationRoot = obj as Bone;
|
|
675
|
-
// return this.animationRoot;
|
|
676
|
-
// }
|
|
677
|
-
// if (obj.children) {
|
|
678
|
-
// for (const ch of obj.children) {
|
|
679
|
-
// const res = this.findRootBone(ch);
|
|
680
|
-
// if (res) return res;
|
|
681
|
-
// }
|
|
682
|
-
// }
|
|
683
|
-
// return null;
|
|
684
|
-
// }
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
class TrackEvaluationWrapper {
|
|
688
|
-
|
|
689
|
-
track?: KeyframeTrack;
|
|
690
|
-
createdInterpolant?: any;
|
|
691
|
-
originalEvaluate?: Function;
|
|
692
|
-
private customEvaluate?: (time: number) => any;
|
|
693
|
-
|
|
694
|
-
constructor(track: KeyframeTrack, evaluate: (time: number, value: any) => any) {
|
|
695
|
-
this.track = track;
|
|
696
|
-
const t = track as any;
|
|
697
|
-
const createOriginalInterpolator = t.createInterpolant.bind(track);
|
|
698
|
-
t.createInterpolant = () => {
|
|
699
|
-
t.createInterpolant = createOriginalInterpolator;
|
|
700
|
-
this.createdInterpolant = createOriginalInterpolator();
|
|
701
|
-
this.originalEvaluate = this.createdInterpolant.evaluate.bind(this.createdInterpolant);
|
|
702
|
-
this.customEvaluate = time => {
|
|
703
|
-
if (!this.originalEvaluate) return;
|
|
704
|
-
const res = this.originalEvaluate(time);
|
|
705
|
-
return evaluate(time, res);
|
|
706
|
-
};
|
|
707
|
-
this.createdInterpolant.evaluate = this.customEvaluate;
|
|
708
|
-
return this.createdInterpolant;
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
dispose() {
|
|
714
|
-
if (this.createdInterpolant && this.originalEvaluate) {
|
|
715
|
-
this.createdInterpolant.evaluate = this.originalEvaluate;
|
|
716
|
-
}
|
|
717
|
-
this.track = undefined;
|
|
718
|
-
this.createdInterpolant = null;
|
|
719
|
-
this.originalEvaluate = undefined;
|
|
720
|
-
this.customEvaluate = undefined;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
class RootMotionAction {
|
|
725
|
-
|
|
726
|
-
private static lastObjPosition: { [key: string]: Vector3 } = {};
|
|
727
|
-
private static lastObjRotation: { [key: string]: Quaternion } = {};
|
|
728
|
-
|
|
729
|
-
// we remove the first keyframe rotation from the space rotation when updating
|
|
730
|
-
private static firstKeyframeRotation: { [key: string]: Quaternion } = {};
|
|
731
|
-
// this is used to rotate the space on clip end / start (so the transform direction is correct)
|
|
732
|
-
private static spaceRotation: { [key: string]: Quaternion } = {};
|
|
733
|
-
private static effectiveSpaceRotation: { [key: string]: Quaternion } = {};
|
|
734
|
-
private static clipOffsetRotation: { [key: string]: Quaternion } = {};
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
set action(val: AnimationAction) {
|
|
738
|
-
this._action = val;
|
|
739
|
-
}
|
|
740
|
-
get action() {
|
|
741
|
-
return this._action;
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
get cacheId() {
|
|
745
|
-
return this.root.uuid;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
private _action!: AnimationAction;
|
|
749
|
-
|
|
750
|
-
private root: Object3D;
|
|
751
|
-
private clip: AnimationClip;
|
|
752
|
-
private positionWrapper: TrackEvaluationWrapper | null = null;
|
|
753
|
-
private rotationWrapper: TrackEvaluationWrapper | null = null;
|
|
754
|
-
private context: Context;
|
|
755
|
-
|
|
756
|
-
positionChange: Vector3 = new Vector3();
|
|
757
|
-
rotationChange: Quaternion = new Quaternion();
|
|
758
|
-
|
|
759
|
-
constructor(context: Context, root: Object3D, clip: AnimationClip, positionTrack: KeyframeTrack | null, rotationTrack: KeyframeTrack | null) {
|
|
760
|
-
// console.log(this, positionTrack, rotationTrack);
|
|
761
|
-
this.context = context;
|
|
762
|
-
this.root = root;
|
|
763
|
-
this.clip = clip;
|
|
764
|
-
|
|
765
|
-
if (!RootMotionAction.firstKeyframeRotation[this.cacheId])
|
|
766
|
-
RootMotionAction.firstKeyframeRotation[this.cacheId] = new Quaternion();
|
|
767
|
-
if (rotationTrack) {
|
|
768
|
-
const values = rotationTrack.values;
|
|
769
|
-
RootMotionAction.firstKeyframeRotation[this.cacheId]
|
|
770
|
-
.set(values[0], values[1], values[2], values[3])
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
if (!RootMotionAction.spaceRotation[this.cacheId])
|
|
774
|
-
RootMotionAction.spaceRotation[this.cacheId] = new Quaternion();
|
|
775
|
-
|
|
776
|
-
if (!RootMotionAction.effectiveSpaceRotation[this.cacheId])
|
|
777
|
-
RootMotionAction.effectiveSpaceRotation[this.cacheId] = new Quaternion();
|
|
778
|
-
|
|
779
|
-
RootMotionAction.clipOffsetRotation[this.cacheId] = new Quaternion();
|
|
780
|
-
if (rotationTrack) {
|
|
781
|
-
RootMotionAction.clipOffsetRotation[this.cacheId]
|
|
782
|
-
.set(rotationTrack.values[0], rotationTrack.values[1], rotationTrack.values[2], rotationTrack.values[3])
|
|
783
|
-
.invert();
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
this.handlePosition(clip, positionTrack);
|
|
787
|
-
this.handleRotation(clip, rotationTrack);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
onStart(action: AnimationAction) {
|
|
791
|
-
if (action.getClip() !== this.clip) return;
|
|
792
|
-
|
|
793
|
-
if (!RootMotionAction.lastObjRotation[this.cacheId]) {
|
|
794
|
-
RootMotionAction.lastObjRotation[this.cacheId] = this.root.quaternion.clone()
|
|
795
|
-
}
|
|
796
|
-
const lastRotation = RootMotionAction.lastObjRotation[this.cacheId];
|
|
797
|
-
// const firstKeyframe = RootMotionAction.firstKeyframeRotation[this.this.cacheId];
|
|
798
|
-
// lastRotation.invert().premultiply(firstKeyframe).invert();
|
|
799
|
-
RootMotionAction.spaceRotation[this.cacheId].copy(lastRotation);
|
|
800
|
-
|
|
801
|
-
if (debugRootMotion) {
|
|
802
|
-
const euler = new Euler().setFromQuaternion(lastRotation);
|
|
803
|
-
console.log("START", this.clip.name, Mathf.toDegrees(euler.y), this.root.position.z);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
private getClipRotationOffset() {
|
|
808
|
-
return RootMotionAction.clipOffsetRotation[this.cacheId];
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
private _prevTime = 0;
|
|
812
|
-
|
|
813
|
-
private handlePosition(_clip: AnimationClip, track: KeyframeTrack | null) {
|
|
814
|
-
if (track) {
|
|
815
|
-
|
|
816
|
-
const root = this.root;
|
|
817
|
-
if (debugRootMotion)
|
|
818
|
-
root.add(new AxesHelper());
|
|
819
|
-
|
|
820
|
-
if (!RootMotionAction.lastObjPosition[this.cacheId])
|
|
821
|
-
RootMotionAction.lastObjPosition[this.cacheId] = this.root.position.clone();
|
|
822
|
-
const valuesDiff = new Vector3();
|
|
823
|
-
const valuesPrev = new Vector3();
|
|
824
|
-
// const rotation = new Quaternion();
|
|
825
|
-
this.positionWrapper = new TrackEvaluationWrapper(track, (time, value: Float64Array) => {
|
|
826
|
-
|
|
827
|
-
const weight = this.action.getEffectiveWeight();
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
// reset for testing
|
|
831
|
-
if (debugRootMotion) {
|
|
832
|
-
if (root.position.length() > 8)
|
|
833
|
-
root.position.set(0, root.position.y, 0);
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
if (time > this._prevTime) {
|
|
837
|
-
valuesDiff.set(value[0], value[1], value[2]);
|
|
838
|
-
valuesDiff.sub(valuesPrev);
|
|
839
|
-
valuesDiff.multiplyScalar(weight);
|
|
840
|
-
valuesDiff.applyQuaternion(this.getClipRotationOffset());
|
|
841
|
-
|
|
842
|
-
// RootMotionAction.effectiveSpaceRotation[id].slerp(RootMotionAction.spaceRotation[id], weight);
|
|
843
|
-
valuesDiff.applyQuaternion(root.quaternion);
|
|
844
|
-
this.positionChange.copy(valuesDiff);
|
|
845
|
-
|
|
846
|
-
// this.root.position.add(valuesDiff);
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
valuesPrev.fromArray(value);
|
|
850
|
-
|
|
851
|
-
this._prevTime = time;
|
|
852
|
-
value[0] = 0;
|
|
853
|
-
value[1] = 0;
|
|
854
|
-
value[2] = 0;
|
|
855
|
-
return value;
|
|
856
|
-
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
private static identityQuaternion = new Quaternion();
|
|
862
|
-
|
|
863
|
-
private handleRotation(clip: AnimationClip, track: KeyframeTrack | null) {
|
|
864
|
-
if (track) {
|
|
865
|
-
if (debugRootMotion) {
|
|
866
|
-
const arr = track.values;
|
|
867
|
-
const firstKeyframe = new Euler().setFromQuaternion(new Quaternion(arr[0], arr[1], arr[2], arr[3]));
|
|
868
|
-
console.log(clip.name, track.name, "FIRST ROTATION IN TRACK", Mathf.toDegrees(firstKeyframe.y));
|
|
869
|
-
const i = track.values.length - 4;
|
|
870
|
-
const lastKeyframe = new Quaternion().set(arr[i], arr[i + 1], arr[i + 2], arr[i + 3]);
|
|
871
|
-
const euler = new Euler().setFromQuaternion(lastKeyframe);
|
|
872
|
-
console.log(clip.name, track.name, "LAST ROTATION IN TRACK", Mathf.toDegrees(euler.y));
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
// if (!RootMotionAction.lastObjRotation[root.uuid]) RootMotionAction.lastObjRotation[root.uuid] = new Quaternion();
|
|
876
|
-
// const temp = new Quaternion();
|
|
877
|
-
let prevTime: number = 0;
|
|
878
|
-
const valuesPrev = new Quaternion();
|
|
879
|
-
const valuesDiff = new Quaternion();
|
|
880
|
-
// const summedRot = new Quaternion();
|
|
881
|
-
this.rotationWrapper = new TrackEvaluationWrapper(track, (time, value: Float64Array) => {
|
|
882
|
-
// root.quaternion.copy(RootMotionAction.lastObjRotation[root.uuid]);
|
|
883
|
-
if (time > prevTime) {
|
|
884
|
-
valuesDiff.set(value[0], value[1], value[2], value[3]);
|
|
885
|
-
valuesPrev.invert();
|
|
886
|
-
valuesDiff.multiply(valuesPrev);
|
|
887
|
-
// if(weight < .99) valuesDiff.slerp(RootMotionAction.identityQuaternion, 1 - weight);
|
|
888
|
-
this.rotationChange.copy(valuesDiff);
|
|
889
|
-
// root.quaternion.multiply(valuesDiff);
|
|
890
|
-
}
|
|
891
|
-
// else
|
|
892
|
-
// root.quaternion.multiply(this.getClipRotationOffset());
|
|
893
|
-
|
|
894
|
-
// RootMotionAction.lastObjRotation[root.uuid].copy(root.quaternion);
|
|
895
|
-
valuesPrev.fromArray(value);
|
|
896
|
-
prevTime = time;
|
|
897
|
-
value[0] = 0;
|
|
898
|
-
value[1] = 0;
|
|
899
|
-
value[2] = 0;
|
|
900
|
-
value[3] = 1;
|
|
901
|
-
return value;
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
// private lastPos: Vector3 = new Vector3();
|
|
907
|
-
|
|
908
|
-
onBeforeUpdate(_weight: number) {
|
|
909
|
-
this.positionChange.set(0, 0, 0);
|
|
910
|
-
this.rotationChange.set(0, 0, 0, 1);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
onAfterUpdate(weight: number): boolean {
|
|
914
|
-
if (!this.action) return false;
|
|
915
|
-
weight *= this.action.getEffectiveWeight();
|
|
916
|
-
if (weight <= 0) return false;
|
|
917
|
-
this.positionChange.multiplyScalar(weight);
|
|
918
|
-
this.rotationChange.slerp(RootMotionAction.identityQuaternion, 1 - weight);
|
|
919
|
-
return true;
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
class RootMotionHandler {
|
|
924
|
-
|
|
925
|
-
private controller: AnimatorController;
|
|
926
|
-
private handler: RootMotionAction[] = [];
|
|
927
|
-
private root!: Object3D;
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
private basePosition: Vector3 = new Vector3();
|
|
931
|
-
private baseQuaternion: Quaternion = new Quaternion();
|
|
932
|
-
private baseRotation: Euler = new Euler();
|
|
933
|
-
|
|
934
|
-
constructor(controller: AnimatorController) {
|
|
935
|
-
this.controller = controller;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
createClip(mixer: AnimationMixer, root: Object3D, clip: AnimationClip): AnimationAction {
|
|
939
|
-
this.root = root;
|
|
940
|
-
let rootName = "";
|
|
941
|
-
if (root && "name" in root) {
|
|
942
|
-
rootName = root.name;
|
|
943
|
-
}
|
|
944
|
-
const positionTrack = this.findRootTrack(clip, ".position");
|
|
945
|
-
const rotationTrack = this.findRootTrack(clip, ".quaternion");
|
|
946
|
-
const handler = new RootMotionAction(this.controller.context!, root, clip, positionTrack, rotationTrack);
|
|
947
|
-
this.handler.push(handler);
|
|
948
|
-
|
|
949
|
-
// it is important we do this after the handler is created
|
|
950
|
-
// otherwise we can not hook into threejs interpolators
|
|
951
|
-
const action = mixer.clipAction(clip);
|
|
952
|
-
handler.action = action;
|
|
953
|
-
return action;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
onStart(action: AnimationAction) {
|
|
958
|
-
for (const handler of this.handler) {
|
|
959
|
-
handler.onStart(action);
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
onBeforeUpdate(weight: number) {
|
|
965
|
-
// capture the position of the object
|
|
966
|
-
this.basePosition.copy(this.root.position);
|
|
967
|
-
this.baseQuaternion.copy(this.root.quaternion);
|
|
968
|
-
|
|
969
|
-
for (const hand of this.handler)
|
|
970
|
-
hand.onBeforeUpdate(weight);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
private summedPosition: Vector3 = new Vector3();
|
|
974
|
-
private summedRotation: Quaternion = new Quaternion();
|
|
975
|
-
|
|
976
|
-
onAfterUpdate(weight: number) {
|
|
977
|
-
if (weight <= 0) return;
|
|
978
|
-
// TODO: blend weight properly with root motion (when using timeline blending with animator)
|
|
979
|
-
|
|
980
|
-
// apply the accumulated changes
|
|
981
|
-
this.root.position.copy(this.basePosition);
|
|
982
|
-
this.root.quaternion.copy(this.baseQuaternion);
|
|
983
|
-
|
|
984
|
-
this.summedPosition.set(0, 0, 0);
|
|
985
|
-
this.summedRotation.set(0, 0, 0, 1);
|
|
986
|
-
for (const entry of this.handler) {
|
|
987
|
-
if (entry.onAfterUpdate(weight)) {
|
|
988
|
-
this.summedPosition.add(entry.positionChange);
|
|
989
|
-
this.summedRotation.multiply(entry.rotationChange);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
this.root.position.add(this.summedPosition);
|
|
993
|
-
this.root.quaternion.multiply(this.summedRotation);
|
|
994
|
-
// RootMotionAction.lastObjRotation[this.root.uuid].copy(this.root.quaternion);
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
private findRootTrack(clip: AnimationClip, name: string) {
|
|
998
|
-
const tracks = clip.tracks;
|
|
999
|
-
if (!tracks) return null;
|
|
1000
|
-
for (const track of tracks) {
|
|
1001
|
-
if (track.name.endsWith(name)) {
|
|
1002
|
-
return track;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return null;
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
class AnimatorControllerSerializator extends TypeSerializer {
|
|
1012
|
-
onSerialize(_: any, _context: SerializationContext) {
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
onDeserialize(data: AnimatorControllerModel & { __type?: string }, context: SerializationContext) {
|
|
1016
|
-
if (context.type === AnimatorController && data?.__type === "AnimatorController")
|
|
1017
|
-
return new AnimatorController(data);
|
|
1018
|
-
return undefined;
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1
|
+
import { Animator } from "./Animator.js";
|
|
2
|
+
import type { AnimatorControllerModel, Condition, State, Transition } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
3
|
+
import { AnimatorConditionMode, AnimatorControllerParameterType, AnimatorStateInfo, createMotion, StateMachineBehaviour } from "../engine/extensions/NEEDLE_animator_controller_model.js";
|
|
4
|
+
import { AnimationAction, AnimationClip, AnimationMixer, AxesHelper, Euler, KeyframeTrack, LoopOnce, Object3D, Quaternion, Vector3 } from "three";
|
|
5
|
+
import { deepClone, getParam } from "../engine/engine_utils.js";
|
|
6
|
+
import { Context } from "../engine/engine_setup.js";
|
|
7
|
+
import { TypeStore } from "../engine/engine_typestore.js";
|
|
8
|
+
import { SerializationContext, TypeSerializer, assign } from "../engine/engine_serialization_core.js";
|
|
9
|
+
import { Mathf } from "../engine/engine_math.js";
|
|
10
|
+
import { isAnimationAction } from "../engine/engine_three_utils.js";
|
|
11
|
+
import { isDevEnvironment } from "../engine/debug/index.js";
|
|
12
|
+
import { InstantiateIdProvider } from "../engine/engine_networking_instantiate.js";
|
|
13
|
+
|
|
14
|
+
const debug = getParam("debuganimatorcontroller");
|
|
15
|
+
const debugRootMotion = getParam("debugrootmotion");
|
|
16
|
+
|
|
17
|
+
function stringToHash(str): number {
|
|
18
|
+
let hash = 0;
|
|
19
|
+
for (let i = 0; i < str.length; i++) {
|
|
20
|
+
const char = str.charCodeAt(i);
|
|
21
|
+
hash = ((hash << 5) - hash) + char;
|
|
22
|
+
hash = hash & hash;
|
|
23
|
+
}
|
|
24
|
+
return hash;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare type CreateAnimatorControllerOptions = {
|
|
28
|
+
/** Should each animationstate loop */
|
|
29
|
+
looping?: boolean,
|
|
30
|
+
/** Set to false to disable generating transitions between animationclips */
|
|
31
|
+
autoTransition?: boolean,
|
|
32
|
+
/** Set to a positive value in seconds for transition duration between states */
|
|
33
|
+
transitionDuration?: number,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class AnimatorController {
|
|
37
|
+
|
|
38
|
+
/** Create an animatorcontroller with clips assigned */
|
|
39
|
+
static createFromClips(clips: AnimationClip[], options: CreateAnimatorControllerOptions = { looping: false, autoTransition: true, transitionDuration: 0 }): AnimatorController {
|
|
40
|
+
const states: State[] = [];
|
|
41
|
+
for (let i = 0; i < clips.length; i++) {
|
|
42
|
+
const clip = clips[i];
|
|
43
|
+
const transitions: Transition[] = [];
|
|
44
|
+
|
|
45
|
+
if (options.autoTransition !== false) {
|
|
46
|
+
const dur = options.transitionDuration ?? 0;
|
|
47
|
+
const normalizedDuration = dur / clip.duration;
|
|
48
|
+
// automatically transition to self by default
|
|
49
|
+
let nextState = i;
|
|
50
|
+
if (options.autoTransition === undefined || options.autoTransition === true) {
|
|
51
|
+
nextState = (i + 1) % clips.length;
|
|
52
|
+
}
|
|
53
|
+
transitions.push({
|
|
54
|
+
exitTime: 1 - normalizedDuration,
|
|
55
|
+
offset: 0,
|
|
56
|
+
duration: dur,
|
|
57
|
+
hasExitTime: true,
|
|
58
|
+
destinationState: nextState,
|
|
59
|
+
conditions: [],
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const state: State = {
|
|
64
|
+
name: clip.name,
|
|
65
|
+
hash: i, // by using the index it's easy for users to call play(2) to play the clip at index 2
|
|
66
|
+
motion: {
|
|
67
|
+
name: clip.name,
|
|
68
|
+
clip: clip,
|
|
69
|
+
isLooping: options?.looping ?? false,
|
|
70
|
+
},
|
|
71
|
+
transitions: transitions,
|
|
72
|
+
behaviours: []
|
|
73
|
+
}
|
|
74
|
+
states.push(state);
|
|
75
|
+
}
|
|
76
|
+
const model: AnimatorControllerModel = {
|
|
77
|
+
name: "AnimatorController",
|
|
78
|
+
guid: new InstantiateIdProvider(Date.now()).generateUUID(),
|
|
79
|
+
parameters: [],
|
|
80
|
+
layers: [{
|
|
81
|
+
name: "Base Layer",
|
|
82
|
+
stateMachine: {
|
|
83
|
+
defaultState: 0,
|
|
84
|
+
states: states
|
|
85
|
+
}
|
|
86
|
+
}]
|
|
87
|
+
}
|
|
88
|
+
const controller = new AnimatorController(model);
|
|
89
|
+
return controller;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
play(name: string | number, layerIndex: number = -1, normalizedTime: number = Number.NEGATIVE_INFINITY, durationInSec: number = 0) {
|
|
93
|
+
if (layerIndex < 0) layerIndex = 0;
|
|
94
|
+
else if (layerIndex >= this.model.layers.length) {
|
|
95
|
+
console.warn("invalid layer");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const layer = this.model.layers[layerIndex];
|
|
99
|
+
const sm = layer.stateMachine;
|
|
100
|
+
for (const state of sm.states) {
|
|
101
|
+
if (state.name === name || state.hash === name) {
|
|
102
|
+
if (debug)
|
|
103
|
+
console.log("transition to ", state);
|
|
104
|
+
this.transitionTo(state, durationInSec, normalizedTime);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
console.warn("Could not find " + name + " to play");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
reset() {
|
|
112
|
+
this.setStartTransition();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setBool(name: string | number, value: boolean) {
|
|
116
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
117
|
+
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = value);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getBool(name: string | number): boolean {
|
|
121
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
122
|
+
return this.model?.parameters?.find(p => p[key] === name)?.value as boolean ?? false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
setFloat(name: string | number, val: number) {
|
|
126
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
127
|
+
const filtered = this.model?.parameters?.filter(p => p[key] === name);
|
|
128
|
+
filtered.forEach(p => p.value = val);
|
|
129
|
+
return filtered?.length > 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
getFloat(name: string | number): number {
|
|
133
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
134
|
+
return this.model?.parameters?.find(p => p[key] === name)?.value as number ?? 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
setInteger(name: string | number, val: number) {
|
|
138
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
139
|
+
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = val);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getInteger(name: string | number): number {
|
|
143
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
144
|
+
return this.model?.parameters?.find(p => p[key] === name)?.value as number ?? 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
setTrigger(name: string | number) {
|
|
148
|
+
if (debug)
|
|
149
|
+
console.log("SET TRIGGER", name);
|
|
150
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
151
|
+
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = true);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
resetTrigger(name: string | number) {
|
|
155
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
156
|
+
return this.model?.parameters?.filter(p => p[key] === name).forEach(p => p.value = false);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getTrigger(name: string | number): boolean {
|
|
160
|
+
const key = typeof name === "string" ? "name" : "hash";
|
|
161
|
+
return this.model?.parameters?.find(p => p[key] === name)?.value as boolean ?? false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
isInTransition(): boolean {
|
|
165
|
+
return this._activeStates.length > 1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
setSpeed(speed: number) {
|
|
169
|
+
this._speed = speed;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**@deprecated use findState */
|
|
173
|
+
FindState(name: string | number | undefined | null): State | null { return this.findState(name); }
|
|
174
|
+
findState(name: string | number | undefined | null): State | null {
|
|
175
|
+
if (!name) return null;
|
|
176
|
+
if (Array.isArray(this.model.layers)) {
|
|
177
|
+
for (const layer of this.model.layers) {
|
|
178
|
+
for (const state of layer.stateMachine.states) {
|
|
179
|
+
if (state.name === name || state.hash == name) return state;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
normalizedStartOffset: number = 0;
|
|
187
|
+
|
|
188
|
+
private _speed: number = 1;
|
|
189
|
+
|
|
190
|
+
animator?: Animator;
|
|
191
|
+
model: AnimatorControllerModel;
|
|
192
|
+
get context(): Context | undefined | null { return this.animator?.context; }
|
|
193
|
+
get mixer() {
|
|
194
|
+
return this._mixer;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// applyRootMotion(obj: Object3D) {
|
|
198
|
+
// // this.internalApplyRootMotion(obj);
|
|
199
|
+
// }
|
|
200
|
+
|
|
201
|
+
bind(animator: Animator) {
|
|
202
|
+
if (!animator) console.error("AnimatorController.bind: animator is null");
|
|
203
|
+
else if (this.animator !== animator) {
|
|
204
|
+
this.animator = animator;
|
|
205
|
+
this._mixer = new AnimationMixer(this.animator.gameObject);
|
|
206
|
+
this.createActions(this.animator);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
clone() {
|
|
211
|
+
if (typeof this.model === "string") {
|
|
212
|
+
console.warn("AnimatorController has not been resolved, can not create model from string", this.model);
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
// clone runtime controller but dont clone clip or action
|
|
216
|
+
const clonedModel = deepClone(this.model, (_owner, _key, _value) => {
|
|
217
|
+
if (_value === null || _value === undefined) return true;
|
|
218
|
+
// dont clone three Objects
|
|
219
|
+
if (_value.type === "Object3D" || _value.isObject3D === true) return false;
|
|
220
|
+
// dont clone AnimationAction
|
|
221
|
+
if (isAnimationAction(_value)) { //.constructor.name === "AnimationAction") {
|
|
222
|
+
// console.log(_value);
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
// dont clone AnimationClip
|
|
226
|
+
if (_value["tracks"] !== undefined) return false;
|
|
227
|
+
return true;
|
|
228
|
+
}) as AnimatorControllerModel;
|
|
229
|
+
console.assert(clonedModel !== this.model);
|
|
230
|
+
const controller = new AnimatorController(clonedModel);
|
|
231
|
+
return controller;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
update(weight: number) {
|
|
235
|
+
if (!this.animator) return;
|
|
236
|
+
this.evaluateTransitions();
|
|
237
|
+
this.updateActiveStates(weight);
|
|
238
|
+
// We want to update the animation mixer even if there is no active state (e.g. in cases where an empty animator controller is assigned and the timeline runs)
|
|
239
|
+
// if (!this._activeState) return;
|
|
240
|
+
const dt = this.animator.context.time.deltaTime;
|
|
241
|
+
if (this.animator.applyRootMotion) {
|
|
242
|
+
this.rootMotionHandler?.onBeforeUpdate(weight);
|
|
243
|
+
}
|
|
244
|
+
this._mixer.update(dt);
|
|
245
|
+
if (this.animator.applyRootMotion) {
|
|
246
|
+
this.rootMotionHandler?.onAfterUpdate(weight);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
private _mixer!: AnimationMixer;
|
|
252
|
+
private _activeState?: State;
|
|
253
|
+
get activeState(): State | undefined { return this._activeState; }
|
|
254
|
+
|
|
255
|
+
constructor(model: AnimatorControllerModel) {
|
|
256
|
+
this.model = model;
|
|
257
|
+
if (debug) console.log(this);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private _activeStates: State[] = [];
|
|
261
|
+
|
|
262
|
+
private updateActiveStates(weight: number) {
|
|
263
|
+
for (let i = 0; i < this._activeStates.length; i++) {
|
|
264
|
+
const state = this._activeStates[i];
|
|
265
|
+
const motion = state.motion;
|
|
266
|
+
if (!motion.action) {
|
|
267
|
+
this._activeStates.splice(i, 1);
|
|
268
|
+
i--;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const action = motion.action;
|
|
272
|
+
action.weight = weight;
|
|
273
|
+
// console.log(action.getClip().name, action.getEffectiveWeight(), action.isScheduled());
|
|
274
|
+
if ((action.getEffectiveWeight() <= 0 && !action.isRunning())) {
|
|
275
|
+
if (debug)
|
|
276
|
+
console.debug("REMOVE", state.name, action.getEffectiveWeight(), action.isRunning(), action.isScheduled())
|
|
277
|
+
this._activeStates.splice(i, 1);
|
|
278
|
+
i--;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
private setStartTransition() {
|
|
285
|
+
for (const layer of this.model.layers) {
|
|
286
|
+
const sm = layer.stateMachine;
|
|
287
|
+
if (sm.defaultState === undefined) {
|
|
288
|
+
if (debug)
|
|
289
|
+
console.warn("AnimatorController default state is undefined, will assign state 0 as default", layer);
|
|
290
|
+
sm.defaultState = 0;
|
|
291
|
+
}
|
|
292
|
+
const start = sm.states[sm.defaultState];
|
|
293
|
+
this.transitionTo(start, 0, this.normalizedStartOffset);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private evaluateTransitions() {
|
|
298
|
+
let didEnterStateThisFrame = false;
|
|
299
|
+
if (!this._activeState) {
|
|
300
|
+
this.setStartTransition();
|
|
301
|
+
if (!this._activeState) return;
|
|
302
|
+
didEnterStateThisFrame = true;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const state = this._activeState;
|
|
306
|
+
const action = state.motion.action;
|
|
307
|
+
let index = 0;
|
|
308
|
+
for (const transition of state.transitions) {
|
|
309
|
+
++index;
|
|
310
|
+
// transition without exit time and without condition that transition to itself are ignored
|
|
311
|
+
if (!transition.hasExitTime && transition.conditions.length <= 0) {
|
|
312
|
+
// if (this._activeState && this.getState(transition.destinationState, currentLayer)?.hash === this._activeState.hash)
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
let allConditionsAreMet = true;
|
|
317
|
+
for (const cond of transition.conditions) {
|
|
318
|
+
if (!this.evaluateCondition(cond)) {
|
|
319
|
+
allConditionsAreMet = false;
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!allConditionsAreMet) continue;
|
|
324
|
+
|
|
325
|
+
if (debug && allConditionsAreMet) {
|
|
326
|
+
// console.log("All conditions are met", transition);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (action) {
|
|
330
|
+
const dur = state.motion.clip!.duration;
|
|
331
|
+
const normalizedTime = dur <= 0 ? 1 : Math.abs(action.time / dur);
|
|
332
|
+
let makeTransition = false;
|
|
333
|
+
if (transition.hasExitTime) {
|
|
334
|
+
if (action.timeScale > 0) makeTransition = normalizedTime >= transition.exitTime;
|
|
335
|
+
// When the animation is playing backwards we need to check exit time inverted
|
|
336
|
+
else if(action.timeScale < 0) makeTransition = 1 - normalizedTime >= transition.exitTime;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
makeTransition = true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (makeTransition) {
|
|
343
|
+
// disable triggers for this transition
|
|
344
|
+
for (const cond of transition.conditions) {
|
|
345
|
+
const param = this.model.parameters.find(p => p.name === cond.parameter);
|
|
346
|
+
if (param?.type === AnimatorControllerParameterType.Trigger && param.value) {
|
|
347
|
+
param.value = false;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// if (transition.hasExitTime && transition.exitTime >= .9999)
|
|
352
|
+
action.clampWhenFinished = true;
|
|
353
|
+
// else action.clampWhenFinished = false;
|
|
354
|
+
if (debug) {
|
|
355
|
+
console.log("transition to " + transition.destinationState, transition, normalizedTime, transition.exitTime, transition.hasExitTime);
|
|
356
|
+
// console.log(action.time, transition.exitTime);
|
|
357
|
+
}
|
|
358
|
+
this.transitionTo(transition.destinationState, transition.duration, transition.offset);
|
|
359
|
+
// use the first transition that matches all conditions and make the transition as soon as in range
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
this.transitionTo(transition.destinationState, transition.duration, transition.offset);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
// if none of the transitions can be made continue searching for another transition meeting the conditions
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// action.time += this.context.time.deltaTime
|
|
371
|
+
// console.log(action?.time, action?.getEffectiveWeight())
|
|
372
|
+
|
|
373
|
+
// update timescale
|
|
374
|
+
if (action) {
|
|
375
|
+
let speedFactor = state.speed ?? 1;
|
|
376
|
+
if (state.speedParameter)
|
|
377
|
+
speedFactor *= this.getFloat(state.speedParameter);
|
|
378
|
+
if (speedFactor !== undefined) {
|
|
379
|
+
action.timeScale = speedFactor * this._speed;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let didTriggerLooping = false;
|
|
384
|
+
if (state.motion.isLooping && action) {
|
|
385
|
+
// we dont use the three loop state here because it prevents the transition check above
|
|
386
|
+
// it is easier if we re-trigger loop here.
|
|
387
|
+
// We also can easily add the cycle offset settings from unity later
|
|
388
|
+
if (action.time >= action.getClip().duration) {
|
|
389
|
+
didTriggerLooping = true;
|
|
390
|
+
action.reset();
|
|
391
|
+
action.time = 0;
|
|
392
|
+
action.play();
|
|
393
|
+
}
|
|
394
|
+
else if (action.time <= 0 && action.timeScale < 0) {
|
|
395
|
+
didTriggerLooping = true;
|
|
396
|
+
action.reset();
|
|
397
|
+
action.time = action.getClip().duration;
|
|
398
|
+
action.play();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// call update state behaviours:
|
|
403
|
+
if (!didTriggerLooping && state && !didEnterStateThisFrame && action && this.animator) {
|
|
404
|
+
if (state.behaviours) {
|
|
405
|
+
const duration = action?.getClip().duration;
|
|
406
|
+
const normalizedTime = action.time / duration;
|
|
407
|
+
const info = new AnimatorStateInfo(this._activeState, normalizedTime, duration, this._speed)
|
|
408
|
+
for (const beh of state.behaviours) {
|
|
409
|
+
if (beh.instance) {
|
|
410
|
+
beh.instance.onStateUpdate?.call(beh.instance, this.animator, info, 0);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
private getState(state: State | number, layerIndex: number): State | null {
|
|
419
|
+
if (typeof state === "number") {
|
|
420
|
+
if (state == -1) {
|
|
421
|
+
state = this.model.layers[layerIndex].stateMachine.defaultState; // exit state -> entry state
|
|
422
|
+
if (state === undefined) {
|
|
423
|
+
if (debug)
|
|
424
|
+
console.warn("AnimatorController default state is undefined: ", this.model, "Layer: " + layerIndex);
|
|
425
|
+
state = 0;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
state = this.model.layers[layerIndex].stateMachine.states[state];
|
|
429
|
+
}
|
|
430
|
+
return state;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
private transitionTo(state: State | number, durationInSec: number, offsetNormalized: number) {
|
|
434
|
+
|
|
435
|
+
if (!this.animator) return;
|
|
436
|
+
|
|
437
|
+
const layerIndex = 0;
|
|
438
|
+
|
|
439
|
+
state = this.getState(state, layerIndex) as State;
|
|
440
|
+
|
|
441
|
+
if (!state?.motion || !state.motion.clip || !(state.motion.clip instanceof AnimationClip)) {
|
|
442
|
+
// if(debug) console.warn("State has no clip or motion", state);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const isSelf = this._activeState === state;
|
|
447
|
+
if (isSelf) {
|
|
448
|
+
const motion = state.motion;
|
|
449
|
+
if (!motion.action_loopback && motion.clip) {
|
|
450
|
+
// uncache action immediately resets the applied animation which breaks the root motion
|
|
451
|
+
// this happens if we have a transition to self and the clip is not cached yet
|
|
452
|
+
const previousMatrix = this.rootMotionHandler ? this.animator.gameObject.matrix.clone() : null;
|
|
453
|
+
this._mixer.uncacheAction(motion.clip, this.animator.gameObject);
|
|
454
|
+
if (previousMatrix)
|
|
455
|
+
previousMatrix.decompose(this.animator.gameObject.position, this.animator.gameObject.quaternion, this.animator.gameObject.scale);
|
|
456
|
+
motion.action_loopback = this.createAction(motion.clip);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// call exit state behaviours
|
|
461
|
+
if (this._activeState?.behaviours && this._activeState.motion.action) {
|
|
462
|
+
const duration = this._activeState?.motion.clip!.duration;
|
|
463
|
+
const normalizedTime = this._activeState.motion.action.time / duration;
|
|
464
|
+
const info = new AnimatorStateInfo(this._activeState, normalizedTime, duration, this._speed);
|
|
465
|
+
for (const beh of this._activeState.behaviours) {
|
|
466
|
+
beh.instance?.onStateExit?.call(beh.instance, this.animator, info, layerIndex);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
const prevAction = this._activeState?.motion.action;
|
|
471
|
+
if (prevAction) {
|
|
472
|
+
prevAction!.fadeOut(durationInSec);
|
|
473
|
+
}
|
|
474
|
+
if (isSelf) {
|
|
475
|
+
state.motion.action = state.motion.action_loopback;
|
|
476
|
+
state.motion.action_loopback = prevAction;
|
|
477
|
+
}
|
|
478
|
+
const prev = this._activeState;
|
|
479
|
+
this._activeState = state;
|
|
480
|
+
|
|
481
|
+
const action = state.motion?.action;
|
|
482
|
+
if (action) {
|
|
483
|
+
|
|
484
|
+
offsetNormalized = Math.max(0, Math.min(1, offsetNormalized));
|
|
485
|
+
if (state.cycleOffsetParameter) {
|
|
486
|
+
let val = this.getFloat(state.cycleOffsetParameter);
|
|
487
|
+
if (typeof val === "number") {
|
|
488
|
+
if (val < 0) val += 1;
|
|
489
|
+
offsetNormalized += val;
|
|
490
|
+
offsetNormalized %= 1;
|
|
491
|
+
}
|
|
492
|
+
else if (debug) console.warn("AnimatorController cycle offset parameter is not a number", state.cycleOffsetParameter);
|
|
493
|
+
}
|
|
494
|
+
else if (typeof state.cycleOffset === "number") {
|
|
495
|
+
offsetNormalized += state.cycleOffset
|
|
496
|
+
offsetNormalized %= 1;
|
|
497
|
+
}
|
|
498
|
+
if (action.isRunning())
|
|
499
|
+
action.stop();
|
|
500
|
+
action.reset();
|
|
501
|
+
action.enabled = true;
|
|
502
|
+
const duration = state.motion.clip!.duration;
|
|
503
|
+
// if we are looping to the same state we don't want to offset the current start time
|
|
504
|
+
action.time = isSelf ? 0 : offsetNormalized * duration;
|
|
505
|
+
if (action.timeScale < 0) action.time = duration - action.time;
|
|
506
|
+
action.clampWhenFinished = true;
|
|
507
|
+
action.setLoop(LoopOnce, 0);
|
|
508
|
+
if (durationInSec > 0)
|
|
509
|
+
action.fadeIn(durationInSec);
|
|
510
|
+
else action.weight = 1;
|
|
511
|
+
action.play();
|
|
512
|
+
|
|
513
|
+
if (this.rootMotionHandler) {
|
|
514
|
+
this.rootMotionHandler.onStart(action);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (!this._activeStates.includes(state))
|
|
518
|
+
this._activeStates.push(state);
|
|
519
|
+
|
|
520
|
+
// call enter state behaviours
|
|
521
|
+
if (this._activeState.behaviours) {
|
|
522
|
+
const info = new AnimatorStateInfo(state, offsetNormalized, duration, this._speed);
|
|
523
|
+
for (const beh of this._activeState.behaviours) {
|
|
524
|
+
beh.instance?.onStateEnter?.call(beh.instance, this.animator, info, layerIndex);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
else if (debug) {
|
|
529
|
+
if (!state["__warned_no_motion"]) {
|
|
530
|
+
state["__warned_no_motion"] = true;
|
|
531
|
+
console.warn("No action", state.motion, this);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (debug)
|
|
536
|
+
console.log("TRANSITION FROM " + prev?.name + " TO " + state.name, durationInSec, prevAction, action, action?.getEffectiveTimeScale(), action?.getEffectiveWeight(), action?.isRunning(), action?.isScheduled(), action?.paused);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
private createAction(clip: AnimationClip) {
|
|
540
|
+
|
|
541
|
+
// uncache clip causes issues when multiple states use the same clip
|
|
542
|
+
// this._mixer.uncacheClip(clip);
|
|
543
|
+
// instead only uncache the action when one already exists to make sure
|
|
544
|
+
// we get unique actions per state
|
|
545
|
+
const existing = this._mixer.existingAction(clip);
|
|
546
|
+
if (existing) this._mixer.uncacheAction(clip, this.animator?.gameObject);
|
|
547
|
+
|
|
548
|
+
if (this.animator?.applyRootMotion) {
|
|
549
|
+
if (!this.rootMotionHandler) {
|
|
550
|
+
this.rootMotionHandler = new RootMotionHandler(this);
|
|
551
|
+
}
|
|
552
|
+
// TODO: find root bone properly
|
|
553
|
+
const root = this.animator.gameObject;
|
|
554
|
+
return this.rootMotionHandler.createClip(this._mixer, root, clip);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
const action = this._mixer.clipAction(clip);
|
|
558
|
+
return action;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
private evaluateCondition(cond: Condition): boolean {
|
|
563
|
+
const param = this.model.parameters.find(p => p.name === cond.parameter);
|
|
564
|
+
if (!param) return false;
|
|
565
|
+
// console.log(param.name, param.value);
|
|
566
|
+
switch (cond.mode) {
|
|
567
|
+
case AnimatorConditionMode.If:
|
|
568
|
+
return param.value === true;
|
|
569
|
+
case AnimatorConditionMode.IfNot:
|
|
570
|
+
return param.value === false;
|
|
571
|
+
case AnimatorConditionMode.Greater:
|
|
572
|
+
return param.value as number > cond.threshold;
|
|
573
|
+
case AnimatorConditionMode.Less:
|
|
574
|
+
return param.value as number < cond.threshold;
|
|
575
|
+
case AnimatorConditionMode.Equals:
|
|
576
|
+
return param.value === cond.threshold;
|
|
577
|
+
case AnimatorConditionMode.NotEqual:
|
|
578
|
+
return param.value !== cond.threshold;
|
|
579
|
+
}
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private createActions(_animator: Animator) {
|
|
584
|
+
// console.trace(this.model, _animator);
|
|
585
|
+
for (const layer of this.model.layers) {
|
|
586
|
+
const sm = layer.stateMachine;
|
|
587
|
+
for (let index = 0; index < sm.states.length; index++) {
|
|
588
|
+
const state = sm.states[index];
|
|
589
|
+
|
|
590
|
+
// ensure we have a transitions array
|
|
591
|
+
if (!state.transitions) {
|
|
592
|
+
state.transitions = [];
|
|
593
|
+
}
|
|
594
|
+
for (const t of state.transitions) {
|
|
595
|
+
// can happen if conditions are empty in blender - the exporter seems to skip empty arrays
|
|
596
|
+
if (!t.conditions) t.conditions = [];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ensure we have a motion even if none was exported
|
|
600
|
+
if (!state.motion) {
|
|
601
|
+
state.motion = createMotion(state.name);
|
|
602
|
+
// console.warn("Missing motion", "AnimatorController: " + this.model.name, state);
|
|
603
|
+
// sm.states.splice(index, 1);
|
|
604
|
+
// index -= 1;
|
|
605
|
+
// continue;
|
|
606
|
+
}
|
|
607
|
+
// the clips array contains which animator has which animationclip
|
|
608
|
+
if (this.animator && state.motion.clips) {
|
|
609
|
+
// TODO: we have to compare by name because on instantiate we clone objects but not the node object
|
|
610
|
+
const mapping = state.motion.clips?.find(e => e.node.name === this.animator?.gameObject?.name);
|
|
611
|
+
// console.log(state.name, mapping?.clip);
|
|
612
|
+
state.motion.clip = mapping?.clip;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ensure we have a clip to blend to
|
|
616
|
+
if (!state.motion.clip) {
|
|
617
|
+
const clip = new AnimationClip(undefined, undefined, []);
|
|
618
|
+
state.motion.clip = clip;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if (state.motion?.clip) {
|
|
622
|
+
const clip = state.motion.clip;
|
|
623
|
+
if (clip instanceof AnimationClip) {
|
|
624
|
+
const action = this.createAction(clip);
|
|
625
|
+
state.motion.action = action;
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
if(debug || isDevEnvironment()) console.warn("No valid animationclip assigned", state);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// create state machine behaviours
|
|
633
|
+
if (state.behaviours && Array.isArray(state.behaviours)) {
|
|
634
|
+
for (const behaviour of state.behaviours) {
|
|
635
|
+
if (!behaviour?.typeName) continue;
|
|
636
|
+
const type = TypeStore.get(behaviour.typeName);
|
|
637
|
+
const instance: StateMachineBehaviour = new type() as StateMachineBehaviour;
|
|
638
|
+
if (instance.isStateMachineBehaviour) {
|
|
639
|
+
instance._context = this.context ?? undefined;
|
|
640
|
+
assign(instance, behaviour.properties);
|
|
641
|
+
behaviour.instance = instance;
|
|
642
|
+
}
|
|
643
|
+
if (debug) console.log("Created animator controller behaviour", state.name, behaviour.typeName, behaviour.properties, instance);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
*enumerateActions() {
|
|
651
|
+
if (!this.model.layers) return;
|
|
652
|
+
for (const layer of this.model.layers) {
|
|
653
|
+
const sm = layer.stateMachine;
|
|
654
|
+
for (let index = 0; index < sm.states.length; index++) {
|
|
655
|
+
const state = sm.states[index];
|
|
656
|
+
if (state?.motion) {
|
|
657
|
+
if (state.motion.action)
|
|
658
|
+
yield state.motion.action;
|
|
659
|
+
if (state.motion.action_loopback)
|
|
660
|
+
yield state.motion.action_loopback;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
// https://docs.unity3d.com/Manual/RootMotion.html
|
|
668
|
+
private rootMotionHandler?: RootMotionHandler;
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
// private findRootBone(obj: Object3D): Object3D | null {
|
|
672
|
+
// if (this.animationRoot) return this.animationRoot;
|
|
673
|
+
// if (obj.type === "Bone") {
|
|
674
|
+
// this.animationRoot = obj as Bone;
|
|
675
|
+
// return this.animationRoot;
|
|
676
|
+
// }
|
|
677
|
+
// if (obj.children) {
|
|
678
|
+
// for (const ch of obj.children) {
|
|
679
|
+
// const res = this.findRootBone(ch);
|
|
680
|
+
// if (res) return res;
|
|
681
|
+
// }
|
|
682
|
+
// }
|
|
683
|
+
// return null;
|
|
684
|
+
// }
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
class TrackEvaluationWrapper {
|
|
688
|
+
|
|
689
|
+
track?: KeyframeTrack;
|
|
690
|
+
createdInterpolant?: any;
|
|
691
|
+
originalEvaluate?: Function;
|
|
692
|
+
private customEvaluate?: (time: number) => any;
|
|
693
|
+
|
|
694
|
+
constructor(track: KeyframeTrack, evaluate: (time: number, value: any) => any) {
|
|
695
|
+
this.track = track;
|
|
696
|
+
const t = track as any;
|
|
697
|
+
const createOriginalInterpolator = t.createInterpolant.bind(track);
|
|
698
|
+
t.createInterpolant = () => {
|
|
699
|
+
t.createInterpolant = createOriginalInterpolator;
|
|
700
|
+
this.createdInterpolant = createOriginalInterpolator();
|
|
701
|
+
this.originalEvaluate = this.createdInterpolant.evaluate.bind(this.createdInterpolant);
|
|
702
|
+
this.customEvaluate = time => {
|
|
703
|
+
if (!this.originalEvaluate) return;
|
|
704
|
+
const res = this.originalEvaluate(time);
|
|
705
|
+
return evaluate(time, res);
|
|
706
|
+
};
|
|
707
|
+
this.createdInterpolant.evaluate = this.customEvaluate;
|
|
708
|
+
return this.createdInterpolant;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
dispose() {
|
|
714
|
+
if (this.createdInterpolant && this.originalEvaluate) {
|
|
715
|
+
this.createdInterpolant.evaluate = this.originalEvaluate;
|
|
716
|
+
}
|
|
717
|
+
this.track = undefined;
|
|
718
|
+
this.createdInterpolant = null;
|
|
719
|
+
this.originalEvaluate = undefined;
|
|
720
|
+
this.customEvaluate = undefined;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
class RootMotionAction {
|
|
725
|
+
|
|
726
|
+
private static lastObjPosition: { [key: string]: Vector3 } = {};
|
|
727
|
+
private static lastObjRotation: { [key: string]: Quaternion } = {};
|
|
728
|
+
|
|
729
|
+
// we remove the first keyframe rotation from the space rotation when updating
|
|
730
|
+
private static firstKeyframeRotation: { [key: string]: Quaternion } = {};
|
|
731
|
+
// this is used to rotate the space on clip end / start (so the transform direction is correct)
|
|
732
|
+
private static spaceRotation: { [key: string]: Quaternion } = {};
|
|
733
|
+
private static effectiveSpaceRotation: { [key: string]: Quaternion } = {};
|
|
734
|
+
private static clipOffsetRotation: { [key: string]: Quaternion } = {};
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
set action(val: AnimationAction) {
|
|
738
|
+
this._action = val;
|
|
739
|
+
}
|
|
740
|
+
get action() {
|
|
741
|
+
return this._action;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
get cacheId() {
|
|
745
|
+
return this.root.uuid;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
private _action!: AnimationAction;
|
|
749
|
+
|
|
750
|
+
private root: Object3D;
|
|
751
|
+
private clip: AnimationClip;
|
|
752
|
+
private positionWrapper: TrackEvaluationWrapper | null = null;
|
|
753
|
+
private rotationWrapper: TrackEvaluationWrapper | null = null;
|
|
754
|
+
private context: Context;
|
|
755
|
+
|
|
756
|
+
positionChange: Vector3 = new Vector3();
|
|
757
|
+
rotationChange: Quaternion = new Quaternion();
|
|
758
|
+
|
|
759
|
+
constructor(context: Context, root: Object3D, clip: AnimationClip, positionTrack: KeyframeTrack | null, rotationTrack: KeyframeTrack | null) {
|
|
760
|
+
// console.log(this, positionTrack, rotationTrack);
|
|
761
|
+
this.context = context;
|
|
762
|
+
this.root = root;
|
|
763
|
+
this.clip = clip;
|
|
764
|
+
|
|
765
|
+
if (!RootMotionAction.firstKeyframeRotation[this.cacheId])
|
|
766
|
+
RootMotionAction.firstKeyframeRotation[this.cacheId] = new Quaternion();
|
|
767
|
+
if (rotationTrack) {
|
|
768
|
+
const values = rotationTrack.values;
|
|
769
|
+
RootMotionAction.firstKeyframeRotation[this.cacheId]
|
|
770
|
+
.set(values[0], values[1], values[2], values[3])
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (!RootMotionAction.spaceRotation[this.cacheId])
|
|
774
|
+
RootMotionAction.spaceRotation[this.cacheId] = new Quaternion();
|
|
775
|
+
|
|
776
|
+
if (!RootMotionAction.effectiveSpaceRotation[this.cacheId])
|
|
777
|
+
RootMotionAction.effectiveSpaceRotation[this.cacheId] = new Quaternion();
|
|
778
|
+
|
|
779
|
+
RootMotionAction.clipOffsetRotation[this.cacheId] = new Quaternion();
|
|
780
|
+
if (rotationTrack) {
|
|
781
|
+
RootMotionAction.clipOffsetRotation[this.cacheId]
|
|
782
|
+
.set(rotationTrack.values[0], rotationTrack.values[1], rotationTrack.values[2], rotationTrack.values[3])
|
|
783
|
+
.invert();
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
this.handlePosition(clip, positionTrack);
|
|
787
|
+
this.handleRotation(clip, rotationTrack);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
onStart(action: AnimationAction) {
|
|
791
|
+
if (action.getClip() !== this.clip) return;
|
|
792
|
+
|
|
793
|
+
if (!RootMotionAction.lastObjRotation[this.cacheId]) {
|
|
794
|
+
RootMotionAction.lastObjRotation[this.cacheId] = this.root.quaternion.clone()
|
|
795
|
+
}
|
|
796
|
+
const lastRotation = RootMotionAction.lastObjRotation[this.cacheId];
|
|
797
|
+
// const firstKeyframe = RootMotionAction.firstKeyframeRotation[this.this.cacheId];
|
|
798
|
+
// lastRotation.invert().premultiply(firstKeyframe).invert();
|
|
799
|
+
RootMotionAction.spaceRotation[this.cacheId].copy(lastRotation);
|
|
800
|
+
|
|
801
|
+
if (debugRootMotion) {
|
|
802
|
+
const euler = new Euler().setFromQuaternion(lastRotation);
|
|
803
|
+
console.log("START", this.clip.name, Mathf.toDegrees(euler.y), this.root.position.z);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private getClipRotationOffset() {
|
|
808
|
+
return RootMotionAction.clipOffsetRotation[this.cacheId];
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
private _prevTime = 0;
|
|
812
|
+
|
|
813
|
+
private handlePosition(_clip: AnimationClip, track: KeyframeTrack | null) {
|
|
814
|
+
if (track) {
|
|
815
|
+
|
|
816
|
+
const root = this.root;
|
|
817
|
+
if (debugRootMotion)
|
|
818
|
+
root.add(new AxesHelper());
|
|
819
|
+
|
|
820
|
+
if (!RootMotionAction.lastObjPosition[this.cacheId])
|
|
821
|
+
RootMotionAction.lastObjPosition[this.cacheId] = this.root.position.clone();
|
|
822
|
+
const valuesDiff = new Vector3();
|
|
823
|
+
const valuesPrev = new Vector3();
|
|
824
|
+
// const rotation = new Quaternion();
|
|
825
|
+
this.positionWrapper = new TrackEvaluationWrapper(track, (time, value: Float64Array) => {
|
|
826
|
+
|
|
827
|
+
const weight = this.action.getEffectiveWeight();
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
// reset for testing
|
|
831
|
+
if (debugRootMotion) {
|
|
832
|
+
if (root.position.length() > 8)
|
|
833
|
+
root.position.set(0, root.position.y, 0);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
if (time > this._prevTime) {
|
|
837
|
+
valuesDiff.set(value[0], value[1], value[2]);
|
|
838
|
+
valuesDiff.sub(valuesPrev);
|
|
839
|
+
valuesDiff.multiplyScalar(weight);
|
|
840
|
+
valuesDiff.applyQuaternion(this.getClipRotationOffset());
|
|
841
|
+
|
|
842
|
+
// RootMotionAction.effectiveSpaceRotation[id].slerp(RootMotionAction.spaceRotation[id], weight);
|
|
843
|
+
valuesDiff.applyQuaternion(root.quaternion);
|
|
844
|
+
this.positionChange.copy(valuesDiff);
|
|
845
|
+
|
|
846
|
+
// this.root.position.add(valuesDiff);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
valuesPrev.fromArray(value);
|
|
850
|
+
|
|
851
|
+
this._prevTime = time;
|
|
852
|
+
value[0] = 0;
|
|
853
|
+
value[1] = 0;
|
|
854
|
+
value[2] = 0;
|
|
855
|
+
return value;
|
|
856
|
+
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
private static identityQuaternion = new Quaternion();
|
|
862
|
+
|
|
863
|
+
private handleRotation(clip: AnimationClip, track: KeyframeTrack | null) {
|
|
864
|
+
if (track) {
|
|
865
|
+
if (debugRootMotion) {
|
|
866
|
+
const arr = track.values;
|
|
867
|
+
const firstKeyframe = new Euler().setFromQuaternion(new Quaternion(arr[0], arr[1], arr[2], arr[3]));
|
|
868
|
+
console.log(clip.name, track.name, "FIRST ROTATION IN TRACK", Mathf.toDegrees(firstKeyframe.y));
|
|
869
|
+
const i = track.values.length - 4;
|
|
870
|
+
const lastKeyframe = new Quaternion().set(arr[i], arr[i + 1], arr[i + 2], arr[i + 3]);
|
|
871
|
+
const euler = new Euler().setFromQuaternion(lastKeyframe);
|
|
872
|
+
console.log(clip.name, track.name, "LAST ROTATION IN TRACK", Mathf.toDegrees(euler.y));
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// if (!RootMotionAction.lastObjRotation[root.uuid]) RootMotionAction.lastObjRotation[root.uuid] = new Quaternion();
|
|
876
|
+
// const temp = new Quaternion();
|
|
877
|
+
let prevTime: number = 0;
|
|
878
|
+
const valuesPrev = new Quaternion();
|
|
879
|
+
const valuesDiff = new Quaternion();
|
|
880
|
+
// const summedRot = new Quaternion();
|
|
881
|
+
this.rotationWrapper = new TrackEvaluationWrapper(track, (time, value: Float64Array) => {
|
|
882
|
+
// root.quaternion.copy(RootMotionAction.lastObjRotation[root.uuid]);
|
|
883
|
+
if (time > prevTime) {
|
|
884
|
+
valuesDiff.set(value[0], value[1], value[2], value[3]);
|
|
885
|
+
valuesPrev.invert();
|
|
886
|
+
valuesDiff.multiply(valuesPrev);
|
|
887
|
+
// if(weight < .99) valuesDiff.slerp(RootMotionAction.identityQuaternion, 1 - weight);
|
|
888
|
+
this.rotationChange.copy(valuesDiff);
|
|
889
|
+
// root.quaternion.multiply(valuesDiff);
|
|
890
|
+
}
|
|
891
|
+
// else
|
|
892
|
+
// root.quaternion.multiply(this.getClipRotationOffset());
|
|
893
|
+
|
|
894
|
+
// RootMotionAction.lastObjRotation[root.uuid].copy(root.quaternion);
|
|
895
|
+
valuesPrev.fromArray(value);
|
|
896
|
+
prevTime = time;
|
|
897
|
+
value[0] = 0;
|
|
898
|
+
value[1] = 0;
|
|
899
|
+
value[2] = 0;
|
|
900
|
+
value[3] = 1;
|
|
901
|
+
return value;
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// private lastPos: Vector3 = new Vector3();
|
|
907
|
+
|
|
908
|
+
onBeforeUpdate(_weight: number) {
|
|
909
|
+
this.positionChange.set(0, 0, 0);
|
|
910
|
+
this.rotationChange.set(0, 0, 0, 1);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
onAfterUpdate(weight: number): boolean {
|
|
914
|
+
if (!this.action) return false;
|
|
915
|
+
weight *= this.action.getEffectiveWeight();
|
|
916
|
+
if (weight <= 0) return false;
|
|
917
|
+
this.positionChange.multiplyScalar(weight);
|
|
918
|
+
this.rotationChange.slerp(RootMotionAction.identityQuaternion, 1 - weight);
|
|
919
|
+
return true;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
class RootMotionHandler {
|
|
924
|
+
|
|
925
|
+
private controller: AnimatorController;
|
|
926
|
+
private handler: RootMotionAction[] = [];
|
|
927
|
+
private root!: Object3D;
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
private basePosition: Vector3 = new Vector3();
|
|
931
|
+
private baseQuaternion: Quaternion = new Quaternion();
|
|
932
|
+
private baseRotation: Euler = new Euler();
|
|
933
|
+
|
|
934
|
+
constructor(controller: AnimatorController) {
|
|
935
|
+
this.controller = controller;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
createClip(mixer: AnimationMixer, root: Object3D, clip: AnimationClip): AnimationAction {
|
|
939
|
+
this.root = root;
|
|
940
|
+
let rootName = "";
|
|
941
|
+
if (root && "name" in root) {
|
|
942
|
+
rootName = root.name;
|
|
943
|
+
}
|
|
944
|
+
const positionTrack = this.findRootTrack(clip, ".position");
|
|
945
|
+
const rotationTrack = this.findRootTrack(clip, ".quaternion");
|
|
946
|
+
const handler = new RootMotionAction(this.controller.context!, root, clip, positionTrack, rotationTrack);
|
|
947
|
+
this.handler.push(handler);
|
|
948
|
+
|
|
949
|
+
// it is important we do this after the handler is created
|
|
950
|
+
// otherwise we can not hook into threejs interpolators
|
|
951
|
+
const action = mixer.clipAction(clip);
|
|
952
|
+
handler.action = action;
|
|
953
|
+
return action;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
onStart(action: AnimationAction) {
|
|
958
|
+
for (const handler of this.handler) {
|
|
959
|
+
handler.onStart(action);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
onBeforeUpdate(weight: number) {
|
|
965
|
+
// capture the position of the object
|
|
966
|
+
this.basePosition.copy(this.root.position);
|
|
967
|
+
this.baseQuaternion.copy(this.root.quaternion);
|
|
968
|
+
|
|
969
|
+
for (const hand of this.handler)
|
|
970
|
+
hand.onBeforeUpdate(weight);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
private summedPosition: Vector3 = new Vector3();
|
|
974
|
+
private summedRotation: Quaternion = new Quaternion();
|
|
975
|
+
|
|
976
|
+
onAfterUpdate(weight: number) {
|
|
977
|
+
if (weight <= 0) return;
|
|
978
|
+
// TODO: blend weight properly with root motion (when using timeline blending with animator)
|
|
979
|
+
|
|
980
|
+
// apply the accumulated changes
|
|
981
|
+
this.root.position.copy(this.basePosition);
|
|
982
|
+
this.root.quaternion.copy(this.baseQuaternion);
|
|
983
|
+
|
|
984
|
+
this.summedPosition.set(0, 0, 0);
|
|
985
|
+
this.summedRotation.set(0, 0, 0, 1);
|
|
986
|
+
for (const entry of this.handler) {
|
|
987
|
+
if (entry.onAfterUpdate(weight)) {
|
|
988
|
+
this.summedPosition.add(entry.positionChange);
|
|
989
|
+
this.summedRotation.multiply(entry.rotationChange);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
this.root.position.add(this.summedPosition);
|
|
993
|
+
this.root.quaternion.multiply(this.summedRotation);
|
|
994
|
+
// RootMotionAction.lastObjRotation[this.root.uuid].copy(this.root.quaternion);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
private findRootTrack(clip: AnimationClip, name: string) {
|
|
998
|
+
const tracks = clip.tracks;
|
|
999
|
+
if (!tracks) return null;
|
|
1000
|
+
for (const track of tracks) {
|
|
1001
|
+
if (track.name.endsWith(name)) {
|
|
1002
|
+
return track;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
class AnimatorControllerSerializator extends TypeSerializer {
|
|
1012
|
+
onSerialize(_: any, _context: SerializationContext) {
|
|
1013
|
+
|
|
1014
|
+
}
|
|
1015
|
+
onDeserialize(data: AnimatorControllerModel & { __type?: string }, context: SerializationContext) {
|
|
1016
|
+
if (context.type === AnimatorController && data?.__type === "AnimatorController")
|
|
1017
|
+
return new AnimatorController(data);
|
|
1018
|
+
return undefined;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
1021
|
new AnimatorControllerSerializator(AnimatorController);
|