diff --git a/package.json b/package.json index 423785b4062a037e3d1e94e9c3467f9ff3b1ea59..e7e8f66aa2ce8788a68016f62f96b0a58ad18c50 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "aframe-billboard-component": "^1.0.0", "aframe-extras": "^3.12.4", - "aframe-input-mapping-component": "https://github.com/johnshaughnessy/aframe-input-mapping-component#c369fed", + "aframe-input-mapping-component": "https://github.com/johnshaughnessy/aframe-input-mapping-component#feature/map-to-array", "aframe-physics-extras": "https://github.com/infinitelee/aframe-physics-extras#fix/physics-collider-crash", "aframe-physics-system": "https://github.com/donmccurdy/aframe-physics-system", "aframe-teleport-controls": "https://github.com/netpro2k/aframe-teleport-controls#feature/teleport-origin", diff --git a/src/assets/avatars/BotDefault_Avatar.glb b/src/assets/avatars/BotDefault_Avatar.glb index ccb77bf21362f3a5b2058f59eafd56fa17a55ec4..0784e7354e0fe2e35b3df8329c5587616203b7c3 100644 Binary files a/src/assets/avatars/BotDefault_Avatar.glb and b/src/assets/avatars/BotDefault_Avatar.glb differ diff --git a/src/assets/avatars/BotDefault_Avatar_Unlit.glb b/src/assets/avatars/BotDefault_Avatar_Unlit.glb index ba33589d4c42fe6bf9756d5164f331e9830dab91..850f7552c4183553779dfe0776fb92f042b7f8ca 100644 Binary files a/src/assets/avatars/BotDefault_Avatar_Unlit.glb and b/src/assets/avatars/BotDefault_Avatar_Unlit.glb differ diff --git a/src/assets/avatars/Bot_SingleSkin_Rigged.glb b/src/assets/avatars/Bot_SingleSkin_Rigged.glb deleted file mode 100755 index 468db3fd21422c94a19c67fc3fd5e0d4e7b8e447..0000000000000000000000000000000000000000 Binary files a/src/assets/avatars/Bot_SingleSkin_Rigged.glb and /dev/null differ diff --git a/src/components/animated-robot-hands.js b/src/components/animated-robot-hands.js index ef7b429d177864cc4d78a907f333e5e38411d7f9..1b26402848a8cb641560d76307708c4d77d53352 100644 --- a/src/components/animated-robot-hands.js +++ b/src/components/animated-robot-hands.js @@ -13,24 +13,25 @@ const POSES = { // TODO: When we have analog values of index-finger triggers or middle-finger grips, // it would be nice to animate the hands proportionally to those analog values. AFRAME.registerComponent("animated-robot-hands", { + dependencies: ["animation-mixer"], schema: { leftHand: { type: "selector", default: "#player-left-controller" }, rightHand: { type: "selector", default: "#player-right-controller" } }, init: function() { - window.hands = this; this.playAnimation = this.playAnimation.bind(this); - // Get the three.js object in the scene graph that has the animation data - const root = this.el.querySelector("a-gltf-entity .RootScene").object3D.children[0]; - this.mixer = new THREE.AnimationMixer(root); - this.root = root; + this.mixer = this.el.components["animation-mixer"].mixer; - // Set hands to open pose because the bind pose is funky due + const object3DMap = this.el.object3DMap; + const rootObj = object3DMap.mesh || object3DMap.scene; + this.clipActionObject = rootObj.parent; + + // Set hands to open pose because the bind pose is funky dues // to the workaround for FBX2glTF animations. - this.openL = this.mixer.clipAction(POSES.open + "_L", root.parent); - this.openR = this.mixer.clipAction(POSES.open + "_R", root.parent); + this.openL = this.mixer.clipAction(POSES.open + "_L", this.clipActionObject); + this.openR = this.mixer.clipAction(POSES.open + "_R", this.clipActionObject); this.openL.play(); this.openR.play(); }, @@ -45,10 +46,6 @@ AFRAME.registerComponent("animated-robot-hands", { this.data.rightHand.removeEventListener("hand-pose", this.playAnimation); }, - tick: function(t, dt) { - this.mixer.update(dt / 1000); - }, - // Animate from pose to pose. // TODO: Transition from current pose (which may be BETWEEN two other poses) // to the target pose, rather than stopping previous actions altogether. @@ -81,8 +78,8 @@ AFRAME.registerComponent("animated-robot-hands", { // console.log( // `Animating ${isLeft ? "left" : "right"} hand from ${prevPose} to ${currPose} over ${duration} seconds.` // ); - const from = mixer.clipAction(prevPose, this.root.parent); - const to = mixer.clipAction(currPose, this.root.parent); + const from = mixer.clipAction(prevPose, this.clipActionObject); + const to = mixer.clipAction(currPose, this.clipActionObject); from.fadeOut(duration); to.fadeIn(duration); to.play(); diff --git a/src/components/animation-mixer.js b/src/components/animation-mixer.js new file mode 100644 index 0000000000000000000000000000000000000000..791854f1eab2b6f30f20f094b9fb9a35c3ecb9f2 --- /dev/null +++ b/src/components/animation-mixer.js @@ -0,0 +1,36 @@ +AFRAME.registerComponent("animation-mixer", { + init() { + this.mixer = null; + + const object3DMap = this.el.object3DMap; + const rootObject3D = object3DMap.mesh || object3DMap.scene; + + if (rootObject3D) { + this.setAnimationMixer(rootObject3D); + } else { + this.onModelLoaded = this.onModelLoaded.bind(this); + this.el.addEventListener("model-loaded", this.onModelLoaded); + } + }, + + onModelLoaded(event) { + const sceneObject3D = event.detail.model; + this.setAnimationMixer(sceneObject3D); + + this.el.removeEventListener(this.onModelLoaded); + }, + + setAnimationMixer(rootObject3D) { + this.mixer = new THREE.AnimationMixer(rootObject3D); + }, + + tick: function(t, dt) { + if (this.mixer) { + this.mixer.update(dt / 1000); + } + }, + + destroy() { + this.el.removeEventListener(this.onModelLoaded); + } +}); diff --git a/src/components/loop-animation.js b/src/components/loop-animation.js new file mode 100644 index 0000000000000000000000000000000000000000..09a9e9dafabf8c05c7f13a02a9ecb820018ef573 --- /dev/null +++ b/src/components/loop-animation.js @@ -0,0 +1,58 @@ +AFRAME.registerComponent("loop-animation", { + dependencies: ["animation-mixer"], + schema: { + clip: { type: "string", required: true } + }, + init() { + const object3DMap = this.el.object3DMap; + this.model = object3DMap.mesh || object3DMap.scene; + + if (this.model) { + this.mixer = this.el.components["animation-mixer"].mixer; + } else { + this.onModelLoaded = this.onModelLoaded.bind(this); + this.el.addEventListener("model-loaded", this.onModelLoaded); + } + }, + + onModelLoaded(event) { + const animationMixerComponent = this.el.components["animation-mixer"]; + this.model = event.detail.model; + this.mixer = animationMixerComponent.mixer; + + this.updateClipState(true); + + this.el.removeEventListener(this.onModelLoaded); + }, + + update(oldData) { + if (oldData.clip !== this.data.clip && this.model) { + this.updateClipState(true); + } + }, + + updateClipState(play) { + const model = this.model; + const clipName = this.data.clip; + + for (const clip of this.model.animations) { + if (clip.name === clipName) { + const action = this.mixer.clipAction(clip, model.parent); + + if (play) { + action.enabled = true; + action.setLoop(THREE.LoopRepeat, Infinity).play(); + } else { + action.stop(); + } + + break; + } + } + }, + + destroy() { + this.updateClipState(false); + this.el.removeEventListener(this.onModelLoaded); + } +}); diff --git a/src/gltf-component-mappings.js b/src/gltf-component-mappings.js index e73692a8ff9270985f3b533ff8bd1f8fdc0cb835..e4cf086733ad1e0dc547abafe3fb37ed025a5608 100644 --- a/src/gltf-component-mappings.js +++ b/src/gltf-component-mappings.js @@ -1,3 +1,4 @@ import "./elements/a-gltf-entity"; AFRAME.AGLTFEntity.registerComponent("scale-audio-feedback", "scale-audio-feedback"); +AFRAME.AGLTFEntity.registerComponent("loop-animation", "loop-animation"); diff --git a/src/room.html b/src/room.html index 3e9b26297f6b592f1ec4a26ac6bfeebb9c0ab562..4d21e693f79f705f3958a388184379e777b34bc4 100644 --- a/src/room.html +++ b/src/room.html @@ -60,6 +60,10 @@ <a-entity class="right-controller"></a-entity> <a-gltf-entity src="#bot-skinned-mesh" inflate="true" ik-controller > + <template data-selector=".RootScene"> + <a-entity animation-mixer ></a-entity> + </template> + <template data-selector=".Neck"> <a-entity> <a-entity @@ -147,7 +151,6 @@ wasd-to-analog2d character-controller="pivot: #player-camera" ik-root - animated-robot-hands > <a-entity id="player-camera" @@ -183,7 +186,11 @@ haptic-feedback ></a-entity> - <a-gltf-entity src="#bot-skinned-mesh" inflate="true" ik-controller> + <a-gltf-entity src="#bot-skinned-mesh" inflate="true" ik-controller > + <template data-selector=".RootScene"> + <a-entity animation-mixer animated-robot-hands ></a-entity> + </template> + <template data-selector=".Neck"> <a-entity> <a-entity class="nametag" visible="false" text ></a-entity> diff --git a/src/room.js b/src/room.js index d19eacda88ff4cb32c104475dc3ddcf769d64a7d..92adbce7b00821fcd5660f3737fe92731336c64f 100644 --- a/src/room.js +++ b/src/room.js @@ -13,9 +13,6 @@ import "aframe-input-mapping-component"; import "aframe-billboard-component"; import "webrtc-adapter"; -import animationMixer from "aframe-extras/src/loaders/animation-mixer"; -AFRAME.registerComponent("animation-mixer", animationMixer); - import { vive_trackpad_dpad4 } from "./behaviours/vive-trackpad-dpad4"; import { oculus_touch_joystick_dpad4 } from "./behaviours/oculus-touch-joystick-dpad4"; import { PressedMove } from "./activators/pressedmove"; @@ -40,6 +37,8 @@ import "./components/layers"; import "./components/spawn-controller"; import "./components/animated-robot-hands"; import "./components/hide-when-quality"; +import "./components/animation-mixer"; +import "./components/loop-animation"; import "./systems/personal-space-bubble"; diff --git a/yarn.lock b/yarn.lock index cc36d0be7b75f6a30e22f154be8f3487f3c5a9f5..8fb5a456961d97ae9975a5df0ad769a7b415e695 100644 --- a/yarn.lock +++ b/yarn.lock @@ -73,9 +73,9 @@ aframe-extras@^3.12.4: aframe-physics-system "^1.4.3" three-pathfinding "^0.2.2" -"aframe-input-mapping-component@https://github.com/johnshaughnessy/aframe-input-mapping-component#c369fed": +"aframe-input-mapping-component@https://github.com/johnshaughnessy/aframe-input-mapping-component#feature/map-to-array": version "0.1.2" - resolved "https://github.com/johnshaughnessy/aframe-input-mapping-component#c369fed313a708fd1e78179cfc9d0ea64433e5f9" + resolved "https://github.com/johnshaughnessy/aframe-input-mapping-component#4c7e493ad6c4a25eef27d32551c94d8b78541191" aframe-lerp-component@^1.1.0: version "1.1.0"