babylon-mmd
Version:
babylon.js mmd loader and runtime
226 lines (225 loc) • 10.4 kB
TypeScript
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 {};