UNPKG

babylon-mmd

Version:
226 lines (225 loc) 10.4 kB
import type { Material } from "@babylonjs/core/Materials/material"; import { Observable } from "@babylonjs/core/Misc/observable"; import type { Nullable } from "@babylonjs/core/types"; import type { IMmdBindableModelAnimation } from "../Animation/IMmdBindableAnimation"; import type { IMmdRuntimeModelAnimation } from "../Animation/IMmdRuntimeAnimation"; import type { MmdCompositeRuntimeModelAnimation } from "../Animation/mmdCompositeRuntimeModelAnimation"; import type { MmdRuntimeModelAnimation } from "../Animation/mmdRuntimeModelAnimation"; import type { MmdRuntimeModelAnimationContainer } from "../Animation/mmdRuntimeModelAnimationContainer"; import type { IMmdMaterialProxyConstructor } from "../IMmdMaterialProxy"; import type { IMmdModel } from "../IMmdModel"; import type { IMmdRuntimeBone } from "../IMmdRuntimeBone"; import type { IMmdLinkedBoneContainer } from "../IMmdRuntimeLinkedBone"; import type { MmdSkinnedMesh, TrimmedMmdSkinnedMesh } from "../mmdMesh"; import type { IMmdModelCtorPhysicsOptions } from "../mmdModel"; import { type MmdRuntimeAnimationHandle } from "../mmdRuntimeAnimationHandle"; import type { MmdWasmAnimation } from "./Animation/mmdWasmAnimation"; import type { MmdWasmRuntimeModelAnimation } from "./Animation/mmdWasmRuntimeModelAnimation"; import { MmdWasmMorphController } from "./mmdWasmMorphController"; import type { MmdWasmRuntime } from "./mmdWasmRuntime"; import { MmdWasmRuntimeAnimationEvaluationType } from "./mmdWasmRuntime"; type RuntimeModelAnimation = MmdWasmRuntimeModelAnimation | MmdRuntimeModelAnimation | MmdRuntimeModelAnimationContainer | MmdCompositeRuntimeModelAnimation | IMmdRuntimeModelAnimation; /** * MmdWasmModel is a class that controls the `MmdSkinnedMesh` to animate the Mesh with MMD Wasm Runtime * * The mesh that instantiates `MmdWasmModel` ignores some original implementations of Babylon.js and follows the MMD specifications * * The biggest difference is that the methods that get the absolute transform of `mesh.skeleton.bones` no longer work properly and can only get absolute transform through `mmdModel.worldTransformMatrices` * * Final matrix is guaranteed to be updated after `MmdWasmModel.afterPhysics()` stage * * IMPORTANT: The typed array members of this class are pointers to wasm memory. * Note that when wasm memory is resized, the typed array is no longer valid. * It is designed to always return a valid typed array at the time of a get, * so as long as you don't copy the typed array reference in an instance of this class elsewhere, you are safe. */ export declare class MmdWasmModel implements IMmdModel { /** * Pointer to wasm side MmdModel */ readonly ptr: number; /** * The root mesh of this model */ readonly mesh: MmdSkinnedMesh | TrimmedMmdSkinnedMesh; /** * The skeleton of this model * * This can be a instance of `Skeleton`, or if you are using a humanoid model, it will be referencing a virtualized bone tree * * So MmdWasmModel.metadata.skeleton is not always equal to MmdWasmModel.skeleton */ readonly skeleton: IMmdLinkedBoneContainer; private readonly _worldTransformMatrices; /** * The array of final transform matrices of bones (ie. the matrix sent to shaders) * * This array reference should not be copied elsewhere and must be read and written with minimal scope */ get worldTransformMatrices(): Float32Array; private readonly _boneAnimationStates; /** * Wasm side bone animation states. this value is automatically synchronized with `MmdWasmModel.skeleton` on `MmdWasmModel.beforePhysics()` stage * * repr: [..., positionX, positionY, positionZ, padding, rotationX, rotationY, rotationZ, rotationW, scaleX, scaleY, scaleZ, padding, ...] * * This array reference should not be copied elsewhere and must be read and written with minimal scope */ get boneAnimationStates(): Float32Array; private readonly _ikSolverStates; /** * Uint8Array that stores the state of IK solvers * * If `ikSolverState[MmdModel.runtimeBones[i].ikSolverIndex]` is 0, IK solver of `MmdModel.runtimeBones[i]` is disabled and if it is 1, IK solver is enabled * * This array reference should not be copied elsewhere and must be read and written with minimal scope */ get ikSolverStates(): Uint8Array; private readonly _rigidBodyStates; /** * Uint8Array that stores the state of RigidBody * * - If bone position is driven by physics, the value is 1 * - If bone position is driven by only animation, the value is 0 * * You can get the state of the rigid body by `rigidBodyStates[MmdModel.runtimeBones[i].rigidBodyIndex]` * * This array reference should not be copied elsewhere and must be read and written with minimal scope */ get rigidBodyStates(): Uint8Array; /** * Runtime bones of this model * * You can get the final transform matrix of a bone by `MmdModel.runtimeBones[i].getFinalMatrixToRef()` */ readonly runtimeBones: readonly IMmdRuntimeBone[]; /** * The morph controller of this model * * The `MmdWasmMorphController` not only wrapper of `MorphTargetManager` but also controls the CPU bound morphs (bone, material, group) */ readonly morph: MmdWasmMorphController; private readonly _physicsModel; private readonly _runtime; private readonly _sortedRuntimeBones; /** * Observable triggered when the animation duration is changed * * Value is 30fps frame time duration of the animation */ readonly onAnimationDurationChangedObservable: Observable<number>; private readonly _animationHandleMap; private _currentAnimation; private _needStateReset; /** * Create a MmdWasmModel * * IMPORTANT: when wasm runtime using buffered evaluation, this constructor must be called before waiting for the WasmMmdRuntime.lock * otherwise, it will cause a datarace * @param wasmRuntime MMD WASM runtime * @param ptr Pointer to wasm side MmdModel * @param mmdSkinnedMesh Mesh that able to instantiate `MmdWasmModel` * @param skeleton The virtualized bone container of the mesh * @param materialProxyConstructor The constructor of `IMmdMaterialProxy` * @param wasmMorphIndexMap Mmd morph to WASM morph index map * @param physicsParams Physics options * @param trimMetadata Whether to trim the metadata of the model */ constructor(wasmRuntime: MmdWasmRuntime, ptr: number, mmdSkinnedMesh: MmdSkinnedMesh, skeleton: IMmdLinkedBoneContainer, materialProxyConstructor: Nullable<IMmdMaterialProxyConstructor<Material>>, wasmMorphIndexMap: Int32Array, physicsParams: Nullable<IMmdModelCtorPhysicsOptions>, trimMetadata: boolean); /** * Dispose this model * * Use MmdWasmRuntime.destroyMmdModel instead of this method * * Restore the original bone matrix update behavior * * Dispose the physics resources if the physics is enabled * * @internal */ _dispose(): void; /** * Get the sorted bones of this model * * The bones are sorted by `transformOrder` */ get sortedRuntimeBones(): readonly IMmdRuntimeBone[]; /** * Bind the animation to this model and return a handle to the runtime animation * @param animation MMD animation or MMD model animation group to add * @param retargetingMap Animation bone name to model bone name map * @returns A handle to the runtime animation */ createRuntimeAnimation(animation: IMmdBindableModelAnimation | MmdWasmAnimation, retargetingMap?: { [key: string]: string; }): MmdRuntimeAnimationHandle; /** * Destroy a runtime animation by its handle * @param handle The handle of the runtime animation to destroy * @returns True if the animation was destroyed, false if it was not found */ destroyRuntimeAnimation(handle: MmdRuntimeAnimationHandle): boolean; _destroyRuntimeAnimation(handle: MmdRuntimeAnimationHandle, fromDisposeEvent: boolean): boolean; /** * Set the current animation of this model * * If handle is null, the current animation will be cleared * @param handle The handle of the animation to set as current * @param updateMorphTarget Whether to update morph target manager numMaxInfluencers (default: true) * @throws {Error} if the animation with the handle is not found */ setRuntimeAnimation(handle: Nullable<MmdRuntimeAnimationHandle>, updateMorphTarget?: boolean): void; /** * Get the runtime animation map of this model */ get runtimeAnimations(): ReadonlyMap<MmdRuntimeAnimationHandle, RuntimeModelAnimation>; /** * Get the current animation of this model */ get currentAnimation(): Nullable<RuntimeModelAnimation>; /** * Reset the rigid body positions and velocities of this model */ initializePhysics(): void; /** * Before the "physics stage" and before the "wasm before solver" stage * * This method must be called before the physics stage * * If frameTime is null, animations are not updated * @param frameTime The time elapsed since the last frame in 30fps */ beforePhysicsAndWasm(frameTime: Nullable<number>): void; /** * Before the "physics stage" and after the "wasm before solver" stage */ beforePhysics(): void; /** * After the "physics stage" and before the "wasm after solver" stage */ afterPhysicsAndWasm(): void; /** * After the "physics stage" and after the "wasm after solver" stage * * mmd solvers are run by wasm runtime * * This method must be called after the physics stage */ afterPhysics(): void; private _buildRuntimeSkeleton; private _originalComputeTransformMatrices; private _disableSkeletonWorldMatrixUpdate; private _enableSkeletonWorldMatrixUpdate; private _resetPose; /** * @internal * @param evaluationType New evaluation type */ onEvaluationTypeChanged(evaluationType: MmdWasmRuntimeAnimationEvaluationType): void; /** * @internal * swap the front and back buffer of the world transform matrices */ swapWorldTransformMatricesBuffer(): void; } export {};