UNPKG

babylon-mmd

Version:
221 lines (220 loc) 8.26 kB
import type { Material } from "@babylonjs/core/Materials/material"; import type { Mesh } from "@babylonjs/core/Meshes/mesh"; import type { Observable } from "@babylonjs/core/Misc/observable"; import type { Scene } from "@babylonjs/core/scene"; import type { Nullable } from "@babylonjs/core/types"; import type { IPlayer } from "./Audio/IAudioPlayer"; import type { ILogger } from "./ILogger"; import type { IMmdModel } from "./IMmdModel"; import type { IMmdRuntimeAnimatable } from "./IMmdRuntimeAnimatable"; import type { IMmdLinkedBoneContainer } from "./IMmdRuntimeLinkedBone"; import type { MmdSkinnedMesh } from "./mmdMesh"; import type { IMmdModelCreationOptions } from "./mmdRuntime"; /** * MMD runtime orchestrates several MMD components (models, camera, audio) * * MMD runtime handles updates and synchronization of MMD components * * It can also create and remove runtime components */ export interface IMmdRuntime<TMmdModel extends IMmdModel = IMmdModel> extends ILogger { /** * Whether to automatically initialize rigid bodies transform and velocity (default: true) * * auto physics initialization is triggered when * - animation seek is far from current frame time (more than 2 seconds) * - browser tab is stop rendering and resumed * - animation is played from the frame 0 */ autoPhysicsInitialization: boolean; /** * This observable is notified when animation duration is changed */ readonly onAnimationDurationChangedObservable: Observable<void>; /** * This observable is notified when animation is played */ readonly onPlayAnimationObservable: Observable<void>; /** * This observable is notified when animation is paused */ readonly onPauseAnimationObservable: Observable<void>; /** * This observable is notified when animation is seeked */ readonly onSeekAnimationObservable: Observable<void>; /** * This observable is notified when animation is evaluated (usually every frame) */ readonly onAnimationTickObservable: Observable<void>; /** * Dispose MMD runtime * * Destroy all MMD models and unregister this runtime from scene */ dispose(scene: Scene): void; /** * Create MMD model from mesh that has MMD metadata * * The skeletons in the mesh where the MmdModel was created no longer follow the usual matrix update policy * @param mmdMesh MmdSkinnedMesh * @param options Creation options * @returns MMD model * @throws {Error} if mesh is not `MmdSkinnedMesh` */ createMmdModel<TMaterial extends Material>(mmdSkinedMesh: Mesh, options?: IMmdModelCreationOptions<TMaterial>): TMmdModel; /** * Create MMD model from humanoid mesh and virtual skeleton * * this method is useful for supporting humanoid models, usually used by `HumanoidMmd` * @param mmdSkinedMesh MmdSkinnedMesh * @param skeleton Skeleton or Virtualized skeleton * @param options Creation options */ createMmdModelFromSkeleton<TMaterial extends Material>(mmdSkinedMesh: MmdSkinnedMesh, skeleton: IMmdLinkedBoneContainer, options?: IMmdModelCreationOptions<TMaterial>): TMmdModel; /** * Destroy MMD model * * Dispose all resources used at MMD runtime and restores the skeleton to the usual matrix update policy * * After calling the `destroyMmdModel` once, the mesh is no longer able to `createMmdModel` because the metadata is lost * @param mmdModel MMD model to destroy * @throws {Error} if model is not found */ destroyMmdModel(mmdModel: TMmdModel): void; /** * Queue MMD model to initialize physics * * Actual physics initialization is done by the before physics stage * @param mmdModel MMD model */ initializeMmdModelPhysics(mmdModel: TMmdModel): void; /** * Queue all MMD models to initialize physics * * Actual physics initialization is done by the before physics stage * * If you set onlyAnimated true, it only initializes physics for animated models */ initializeAllMmdModelsPhysics(onlyAnimated: boolean): void; /** * Add Animatable object to the runtime * * Usually this is MMD camera, but you can add any object that implements `IMmdRuntimeAnimatable` * @param animatable Animatable object * @return true if the animatable is added, false if the animatable is already added */ addAnimatable(animatable: IMmdRuntimeAnimatable): boolean; /** * Remove Animatable object from the runtime * @param animatable Animatable object * @return true if the animatable is removed, false if the animatable is not found */ removeAnimatable(animatable: IMmdRuntimeAnimatable): boolean; /** * Set audio player to sync with animation * * If you set up audio Player while playing an animation, it try to play the audio from the current animation time * And returns Promise because this operation is asynchronous. In most cases, you don't have to await this Promise * @param audioPlayer Audio player * @returns Promise */ setAudioPlayer(audioPlayer: Nullable<IPlayer>): Promise<void>; /** * Register MMD runtime to scene * * register `beforePhysics` and `afterPhysics` to scene Observables * * If you need a more complex update method you can call `beforePhysics` and `afterPhysics` manually * @param scene Scene */ register(scene: Scene): void; /** * Unregister MMD runtime from scene * @param scene Scene */ unregister(scene: Scene): void; /** * Before the physics stage, update animations and run MMD runtime solvers * * @param deltaTime Delta time in milliseconds */ beforePhysics(deltaTime: number): void; /** * After the physics stage, update physics and run MMD runtime solvers */ afterPhysics(): void; /** * Play animation from the current animation time * * If audio player is set, it try to play the audio from the current animation time * * It returns Promise because playing audio is asynchronous * @returns Promise */ playAnimation(): Promise<void>; /** * Pause animation */ pauseAnimation(): void; /** * Seek animation to the specified frame time * * If you set forceEvaluate true, the animation is evaluated even if the animation is not playing * * If audio player is set and not paused, it try to play the audio from the seek time so it returns Promise * @param frameTime Time in 30fps frame * @param forceEvaluate Whether to force evaluate animation * @returns Promise */ seekAnimation(frameTime: number, forceEvaluate: boolean): Promise<void>; /** * Whether animation is playing */ get isAnimationPlaying(): boolean; /** * MMD models created by this runtime */ get models(): readonly TMmdModel[]; /** * Animatable objects that added to this runtime */ get animatables(): readonly IMmdRuntimeAnimatable[]; /** * Audio player */ get audioPlayer(): Nullable<IPlayer>; /** * Current animation time scale (default: 1) */ get timeScale(): number; set timeScale(value: number); /** * Current animation time in 30fps frame */ get currentFrameTime(): number; /** * Current animation time in seconds */ get currentTime(): number; /** * Current animation duration in 30fps frame */ get animationFrameTimeDuration(): number; /** * Current animation duration in seconds */ get animationDuration(): number; /** * Set animation duration manually * * When the difference between the length of the song and the length of the animation is large, it can be helpful to adjust the animation duration manually * @param frameTimeDuration Time in 30fps frame */ setManualAnimationDuration(frameTimeDuration: Nullable<number>): void; /** * Enable or disable debug logging (default: false) */ get loggingEnabled(): boolean; set loggingEnabled(value: boolean); }