Bryan
Posted on January 11, 2024
π Stumbled here on accident? Start with the first part!
Welcome back to the 9th and final part of this series about asset handling and animation. In the last article we added a model in form a door to the scene. In the following sections weβre going to implement opening and closing the door on the press of a button.
βΉοΈ Remember - you can always run the code associated with this article and follow along using
npm start --part=9
Interacting with the door
handleControllerSelection() {
...
this._xr.input.onControllerAddedObservable.add((motionControllerAdded) => {
motionControllerAdded.onMotionControllerInitObservable.add((motionControllerInit) => {
...
const buttonComponent = motionControllerInit.getComponent(motionControllerComponentIds[3]);
if (buttonComponent) {
buttonComponent.onButtonStateChangedObservable.add((component) => {
if (component.pressed) {
(this._doorIsOpen) ? this.closeDoor() : this.openDoor();
}
});
}
triggerComponent.onButtonStateChangedObservable.add((component) => {
...
});
});
});
}
First weβre going to add a new interaction to the handleControllerSelectionfunction
by observing button presses to the controllers A-Button
. The motionControllerComponentIds[3]
is the component id related to this specific button.
π More about component ids can be found here.
If the button is pressed the door is either opened by the this.openDoor()
or closed this.closeDoor()
function, depending on the state of this._doorIsOpen
.
Opening the door
openDoor() {
if (this._door !== null) {
this.animateDoor(30);
this._doorIsOpen = true;
}
}
Closing the door
closeDoor() {
if (this._door !== null) {
this.animateDoor(30);
this._doorIsOpen = false;
}
}
By adjusting the duration
we can create an effect where the door opens normally but closes like it is shut. The lower the duration
, the quicker the animation is.
Animating the door interaction
animateDoor(duration: number) {
const animationName = this._doorIsOpen ? "doorOpenQuat" : "doorCloseQuat";
const doorAnimation = new Animation(animationName, "rotationQuaternion", 30, Animation.ANIMATIONTYPE_QUATERNION, Animation.ANIMATIONLOOPMODE_CONSTANT);
const startRotation = this._door!.rotationQuaternion!.clone();
const axis = new Vector3(0, 1, 0);
const angle = this._doorIsOpen ? -Math.PI / 1.5 : Math.PI / 1.5;
const endRotation = Quaternion.RotationAxis(axis, angle).multiply(startRotation);
const keyFrames : {frame: number, value: Quaternion}[] = [];
keyFrames.push({
frame: 0,
value: startRotation
});
keyFrames.push({
frame: duration,
value: endRotation
});
doorAnimation.setKeys(keyFrames);
if (!this._door!.rotationQuaternion) {
this._door!.rotationQuaternion = new Quaternion();
}
this._door!.animations = [doorAnimation];
this._scene.beginAnimation(this._door, 0, duration, false);
}
To enhance the immersion we implement a smooth animation for the opening and closing the door.
-
Animation Definition:
-
animationName
: Determines the name of the animation based on the current state of the door (open or closed). -
doorAnimation
: Creates a newAnimation
object for quaternion rotation. This type of rotation is smooth and avoids issues like gimbal lock. The animation runs at 30 frames per second and doesn't loop.
-
-
Initial Rotation:
- Retrieves the door's current rotation in quaternion form (a complex number system that represents rotations).
-
End Rotation Calculation:
- Defines the rotation axis (y-axis) and the angle (90 degrees for opening, -90 degrees for closing).
- Calculates the end rotation quaternion by multiplying the start rotation by the rotation created from the specified axis and angle.
-
Keyframe Definition:
- Initializes an array for keyframes, which are crucial points in the animation.
- Adds the start (frame 0) and end (frame at
duration
) rotations to the keyframes. This defines the animation path from the current rotation to the target rotation.
-
Animation Assignment:
- Ensures the door is set to use quaternion rotation.
- Assigns the created animation to the door mesh, preparing it to be animated.
-
Begin Animation:
- Starts the animation using the Babylon.js
beginAnimation
method on the door mesh from frame 0 to the specifiedduration
. - The animation is not set to loop.
- Starts the animation using the Babylon.js
Conclusion
In this final part of our series, we delved into the nuances of animating a door in a 3D environment, highlighting the seamless integration of user interactions and realistic motion. Utilizing quaternion rotations and Babylon.js, we demonstrated how to create a smooth and responsive door animation that enhances user experience.
Posted on January 11, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.