### Install dependencies and start development server Source: https://noname0310.github.io/babylon-mmd/docs/get-started/project-setup Commands to install required packages and launch the local development server. ```bash npm install npm start ``` -------------------------------- ### Full SceneBuilder Implementation Source: https://noname0310.github.io/babylon-mmd/docs/get-started/load-and-play-audio A complete example showing the setup of the scene, camera, lighting, and audio player integration. ```typescript import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; import { RegisterPmxLoader } from "babylon-mmd/esm/Loader/pmxLoader.pure"; import { RegisterMmdOutlineRenderer } from "babylon-mmd/esm/Loader/mmdOutlineRenderer.pure"; import { RegisterMmdRuntimeCameraAnimation } from "babylon-mmd/esm/Runtime/Animation/mmdRuntimeCameraAnimation.pure"; import { RegisterMmdRuntimeModelAnimation } from "babylon-mmd/esm/Runtime/Animation/mmdRuntimeModelAnimation.pure"; import type { AbstractEngine } from "@babylonjs/core/Engines/abstractEngine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; import { LoadAssetContainerAsync } from "@babylonjs/core/Loading/sceneLoader"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; import { Vector3 } from "@babylonjs/core/Maths/math.vector"; import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; import { Scene } from "@babylonjs/core/scene"; import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; import { VmdLoader } from "babylon-mmd/esm/Loader/vmdLoader"; import { StreamAudioPlayer } from "babylon-mmd/esm/Runtime/Audio/streamAudioPlayer"; import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera.pure"; import type { MmdMesh } from "babylon-mmd/esm/Runtime/mmdMesh"; import { MmdRuntime } from "babylon-mmd/esm/Runtime/mmdRuntime"; import type { ISceneBuilder } from "./baseRuntime"; RegisterPmxLoader(); RegisterMmdOutlineRenderer(); RegisterMmdRuntimeCameraAnimation(); RegisterMmdRuntimeModelAnimation(); export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { const materialBuilder = new MmdStandardMaterialBuilder(); const scene = new Scene(engine); scene.clearColor = new Color4(0.95, 0.95, 0.95, 1.0); scene.ambientColor = new Color3(0.5, 0.5, 0.5); const mmdCamera = new MmdCamera("MmdCamera", new Vector3(0, 10, 0), scene); const directionalLight = new DirectionalLight("DirectionalLight", new Vector3(0.5, -1, 1), scene); directionalLight.intensity = 1.0; directionalLight.autoCalcShadowZBounds = true; const shadowGenerator = new ShadowGenerator(1024, directionalLight, true); shadowGenerator.transparencyShadow = true; shadowGenerator.usePercentageCloserFiltering = true; shadowGenerator.forceBackFacesOnly = true; shadowGenerator.filteringQuality = ShadowGenerator.QUALITY_MEDIUM; shadowGenerator.frustumEdgeFalloff = 0.1; const ground = CreateGround("ground1", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene); ground.receiveShadows = true; const audioPlayer = new StreamAudioPlayer(scene); ``` -------------------------------- ### Full MMD Scene Implementation Source: https://noname0310.github.io/babylon-mmd/docs/get-started/load-mmd-model A complete example showing the setup of a scene, MMD camera, directional light, shadow generator, and model loading. ```typescript import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; import { RegisterPmxLoader } from "babylon-mmd/esm/Loader/pmxLoader.pure"; import { RegisterMmdOutlineRenderer } from "babylon-mmd/esm/Loader/mmdOutlineRenderer.pure"; import type { AbstractEngine } from "@babylonjs/core/Engines/abstractEngine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; import { LoadAssetContainerAsync } from "@babylonjs/core/Loading/sceneLoader"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; import { Vector3 } from "@babylonjs/core/Maths/math.vector"; import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; import { Scene } from "@babylonjs/core/scene"; import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera.pure"; import type { MmdMesh } from "babylon-mmd/esm/Runtime/mmdMesh"; import type { ISceneBuilder } from "./baseRuntime"; RegisterPmxLoader(); RegisterMmdOutlineRenderer(); export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { const materialBuilder = new MmdStandardMaterialBuilder(); const scene = new Scene(engine); scene.clearColor = new Color4(0.95, 0.95, 0.95, 1.0); scene.ambientColor = new Color3(0.5, 0.5, 0.5); const mmdCamera = new MmdCamera("MmdCamera", new Vector3(0, 10, 0), scene); const directionalLight = new DirectionalLight("DirectionalLight", new Vector3(0.5, -1, 1), scene); directionalLight.intensity = 1.0; directionalLight.autoCalcShadowZBounds = true; const shadowGenerator = new ShadowGenerator(1024, directionalLight, true); shadowGenerator.transparencyShadow = true; shadowGenerator.usePercentageCloserFiltering = true; shadowGenerator.forceBackFacesOnly = true; shadowGenerator.filteringQuality = ShadowGenerator.QUALITY_MEDIUM; shadowGenerator.frustumEdgeFalloff = 0.1; const ground = CreateGround("ground1", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene); ground.receiveShadows = true; const modelMesh = await LoadAssetContainerAsync( "res/private_test/model/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene, { pluginOptions: { mmdmodel: { loggingEnabled: true, materialBuilder: materialBuilder } } }).then(result => { result.addAllToScene(); return result.rootNodes[0] as MmdMesh; }); for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); return scene; } } ``` -------------------------------- ### Importing from the main package Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/material-builder Example of importing symbols from the main babylon-mmd package. ```typescript import { Something } from "babylon-mmd"; ``` -------------------------------- ### Full Physics Scene Implementation Source: https://noname0310.github.io/babylon-mmd/docs/get-started/add-physics Complete setup for an MMD scene including loaders, camera, lighting, and physics runtime initialization. ```typescript import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; import { RegisterPmxLoader } from "babylon-mmd/esm/Loader/pmxLoader.pure"; import { RegisterMmdOutlineRenderer } from "babylon-mmd/esm/Loader/mmdOutlineRenderer.pure"; import { RegisterMmdRuntimeCameraAnimation } from "babylon-mmd/esm/Runtime/Animation/mmdRuntimeCameraAnimation.pure"; import { RegisterMmdRuntimeModelAnimation } from "babylon-mmd/esm/Runtime/Animation/mmdRuntimeModelAnimation.pure"; import type { AbstractEngine } from "@babylonjs/core/Engines/abstractEngine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; import { LoadAssetContainerAsync } from "@babylonjs/core/Loading/sceneLoader"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; import { Vector3 } from "@babylonjs/core/Maths/math.vector"; import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; import { Scene } from "@babylonjs/core/scene"; import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; import { VmdLoader } from "babylon-mmd/esm/Loader/vmdLoader"; import { StreamAudioPlayer } from "babylon-mmd/esm/Runtime/Audio/streamAudioPlayer"; import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera.pure"; import type { MmdMesh } from "babylon-mmd/esm/Runtime/mmdMesh"; import { MmdRuntime } from "babylon-mmd/esm/Runtime/mmdRuntime"; import { MmdWasmInstanceTypeMPR } from "babylon-mmd/esm/Runtime/Optimized/InstanceType/multiPhysicsRelease"; import { GetMmdWasmInstance } from "babylon-mmd/esm/Runtime/Optimized/mmdWasmInstance"; import { MultiPhysicsRuntime } from "babylon-mmd/esm/Runtime/Optimized/Physics/Bind/Impl/multiPhysicsRuntime"; import { MotionType } from "babylon-mmd/esm/Runtime/Optimized/Physics/Bind/motionType"; import { PhysicsStaticPlaneShape } from "babylon-mmd/esm/Runtime/Optimized/Physics/Bind/physicsShape"; import { RigidBody } from "babylon-mmd/esm/Runtime/Optimized/Physics/Bind/rigidBody"; import { RigidBodyConstructionInfo } from "babylon-mmd/esm/Runtime/Optimized/Physics/Bind/rigidBodyConstructionInfo"; import { MmdBulletPhysics } from "babylon-mmd/esm/Runtime/Optimized/Physics/mmdBulletPhysics"; import type { ISceneBuilder } from "./baseRuntime"; RegisterPmxLoader(); RegisterMmdOutlineRenderer(); RegisterMmdRuntimeCameraAnimation(); RegisterMmdRuntimeModelAnimation(); export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { const materialBuilder = new MmdStandardMaterialBuilder(); const scene = new Scene(engine); scene.clearColor = new Color4(0.95, 0.95, 0.95, 1.0); scene.ambientColor = new Color3(0.5, 0.5, 0.5); const mmdCamera = new MmdCamera("MmdCamera", new Vector3(0, 10, 0), scene); const directionalLight = new DirectionalLight("DirectionalLight", new Vector3(0.5, -1, 1), scene); directionalLight.intensity = 1.0; directionalLight.autoCalcShadowZBounds = true; const shadowGenerator = new ShadowGenerator(1024, directionalLight, true); shadowGenerator.transparencyShadow = true; shadowGenerator.usePercentageCloserFiltering = true; shadowGenerator.forceBackFacesOnly = true; ``` -------------------------------- ### VPD File Structure Example Source: https://noname0310.github.io/babylon-mmd/docs/reference/understanding-mmd-behaviour/introduction-to-vmd-and-vpd A sample VPD file showing the header, bone pose definitions with translation and quaternion data, and morph state entries. ```text Vocaloid Pose Data file YYB式初音ミク_10th_v1.02.osm; // 親ファイル名 4; // 総ポーズボーン数 Bone0{右腕捩 0.000000,0.000000,0.000000; // trans x,y,z -0.000000,-0.000000,-0.000000,1.000000; // Quaternion x,y,z,w } Bone1{右ひじ 0.000000,0.000000,0.000000; // trans x,y,z 0.176789,-0.061290,0.747712,0.637114; // Quaternion x,y,z,w } Bone2{右手捩 0.000000,0.000000,0.000000; // trans x,y,z -0.000000,-0.000000,-0.000000,1.000000; // Quaternion x,y,z,w } Bone3{右手首 0.000000,0.000000,0.000000; // trans x,y,z -0.574374,-0.615622,0.113957,0.527368; // Quaternion x,y,z,w } Morph0{う 0.200000; } Morph1{え 0; } ``` -------------------------------- ### Importing from specific modules Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/material-builder Example of importing symbols directly from their definition file for tree-shaking. ```typescript import { Something } from "babylon-mmd/esm/something"; ``` -------------------------------- ### BPMX mesh hierarchy examples Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/the-babylon-pmx-format/bpmx-loader Visual representation of how the mesh hierarchy is structured based on the number of geometries and the useSingleMeshForSingleGeometryModel option. ```text RootMesh { children: [ Mesh1 Mesh2 Mesh3 ] } ``` ```text Mesh1 ``` ```text RootMesh { children: [ Mesh1 ] } ``` -------------------------------- ### Example PMX File Structure Source: https://noname0310.github.io/babylon-mmd/docs/reference/understanding-mmd-behaviour/introduction-to-pmx-and-pmd Visual representation of the relative path structure for textures within a model directory. ```text - model.pmx - textures/ - texture1.png - texture2.png ``` -------------------------------- ### Full SceneBuilder Implementation Source: https://noname0310.github.io/babylon-mmd/docs/get-started/create-basic-scene Complete implementation of the SceneBuilder class including camera, lighting, shadow generation, and ground plane setup. ```typescript import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent"; import type { AbstractEngine } from "@babylonjs/core/Engines/abstractEngine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; import { Vector3 } from "@babylonjs/core/Maths/math.vector"; import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; import { Scene } from "@babylonjs/core/scene"; import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera.pure"; import type { ISceneBuilder } from "./baseRuntime"; export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { const scene = new Scene(engine); scene.clearColor = new Color4(0.95, 0.95, 0.95, 1.0); scene.ambientColor = new Color3(0.5, 0.5, 0.5); const mmdCamera = new MmdCamera("MmdCamera", new Vector3(0, 10, 0), scene); const directionalLight = new DirectionalLight("DirectionalLight", new Vector3(0.5, -1, 1), scene); directionalLight.intensity = 1.0; directionalLight.autoCalcShadowZBounds = true; const shadowGenerator = new ShadowGenerator(1024, directionalLight, true); shadowGenerator.transparencyShadow = true; shadowGenerator.usePercentageCloserFiltering = true; shadowGenerator.forceBackFacesOnly = true; shadowGenerator.filteringQuality = ShadowGenerator.QUALITY_MEDIUM; shadowGenerator.frustumEdgeFalloff = 0.1; const ground = CreateGround("ground1", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene); ground.receiveShadows = true; return scene; } } ``` -------------------------------- ### Alpha Index Assignment Example Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/material-builder Demonstrates how alphaIndex values are assigned to meshes based on model loading order and increments. ```text Model A: { Mesh1: { alphaIndex: 0 } Mesh2: { alphaIndex: 1 } } Model B: { Mesh1: { alphaIndex: 3 } Mesh2: { alphaIndex: 4 } Mesh3: { alphaIndex: 5 } } ``` ```text Model A: { Mesh1: { alphaIndex: 0 } Mesh2: { alphaIndex: 1 } } Model B: { Mesh1: { alphaIndex: 1 } Mesh2: { alphaIndex: 2 } Mesh3: { alphaIndex: 3 } } ``` -------------------------------- ### Load PMX Model and Animation Source: https://noname0310.github.io/babylon-mmd/docs/reference/overview Combines model loading and runtime animation setup into a single workflow. ```typescript const assetContainer = await LoadAssetContainerAsync("path/to/your_file.pmx", scene); assetContainer.addAllToScene(); const mmdMesh = assetContainer.meshes[0] as MmdMesh; const mmdModel = mmdRuntime.createMmdModel(mmdMesh); const modelMotion = await vmdLoader.loadAsync("model_motion", "your_model_motion_path.vmd"); const modelRuntimeAnimationHandle = mmdModel.createRuntimeAnimation(modelMotion); mmdModel.setRuntimeAnimation(modelRuntimeAnimationHandle); ``` -------------------------------- ### Initialize RigidBodyBundle Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/bullet-physics Demonstrates creating multiple rigid bodies efficiently using RigidBodyConstructionInfoList and adding them to the physics world. ```javascript const boxShape = new PhysicsBoxShape(runtime, new Vector3(1, 1, 1)); const rbCount = 10; const rbInfoList = new RigidBodyConstructionInfoList(wasmInstance, rbCount); for (let k = 0; k < rbCount; ++k) { rbInfoList.setShape(k, boxShape); const initialTransform = Matrix.TranslationToRef(xOffset, 1 + k * 2, zOffset, matrix); rbInfoList.setInitialTransform(k, initialTransform); rbInfoList.setFriction(k, 1.0); rbInfoList.setLinearDamping(k, 0.3); rbInfoList.setAngularDamping(k, 0.3); } const boxRigidBodyBundle = new RigidBodyBundle(runtime, rbInfoList); world.addRigidBodyBundle(boxRigidBodyBundle, worldId); ``` -------------------------------- ### Start MMD Animation Playback Source: https://noname0310.github.io/babylon-mmd/docs/reference/overview Triggers animation playback, allowing audio to start before model loading completes. ```typescript // You can also run the animation before it loads. This will allow the audio to run first. mmdRuntime.playAnimation(); ``` -------------------------------- ### Initialize Babylon.js Scene with MMD Camera and Lighting Source: https://noname0310.github.io/babylon-mmd/docs/reference/overview Sets up a basic scene with an MMD-compatible camera and directional light to match MMD material lighting models. ```typescript const scene = new Scene(engine); scene.ambientColor = new Color3(0.5, 0.5, 0.5); const camera = new MmdCamera("mmdCamera", new Vector3(0, 10, 0), scene); const directionalLight = new DirectionalLight("DirectionalLight", new Vector3(0.5, -1, 1), scene); directionalLight.intensity = 1.0; CreateGround("ground1", { width: 60, height: 60, subdivisions: 2, updatable: false }, scene); ``` -------------------------------- ### Initialize sceneBuilder.ts Source: https://noname0310.github.io/babylon-mmd/docs/get-started/project-setup The starting point for configuring the MMD scene by implementing the ISceneBuilder interface. ```typescript import type { AbstractEngine } from "@babylonjs/core/Engines/abstractEngine"; import { Scene } from "@babylonjs/core/scene"; import type { ISceneBuilder } from "./baseRuntime"; export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { const scene = new Scene(engine); return scene; } } ``` -------------------------------- ### VpdLoader.loadFromVpdObjectAsync Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-animation-loader Creates an MmdAnimation from a pre-parsed VpdObject. ```APIDOC ## VpdLoader.loadFromVpdObjectAsync(name: string, vpdObject: VpdObject) ### Description Converts a VpdObject (parsed via VpdReader) into an MmdAnimation. ### Parameters - **name** (string) - Required - The name identifier for the animation. - **vpdObject** (VpdObject) - Required - The parsed VPD data object. ``` -------------------------------- ### MmdAnimationSpan Transition Properties Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/animation/animation-blending Properties for controlling weight transitions (easing) at the start and end of an animation span. ```APIDOC - easeInFrameTime (number): Sets the number of frames for weight to change from 0 to 1 when the animation starts. - easeOutFrameTime (number): Sets the number of frames for weight to change from 1 to 0 when the animation ends. - easingFunction (EasingFunction): Sets the easing function used for weight changes (default: null, linear). ``` -------------------------------- ### Inherit from MaterialBuilderBase Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/material-builder/build-your-own-mmd-material-builder Initial setup for a custom material builder class by extending MaterialBuilderBase and defining the constructor. ```typescript class MyMaterialBuilder extends MaterialBuilderBase { public constructor() { super(MyMaterial); } } ``` -------------------------------- ### Project source structure Source: https://noname0310.github.io/babylon-mmd/docs/get-started/project-setup Overview of the project directory layout. ```text / (root) ├── /res: Folder containing PMX models, VMD animations, MP3 audio, etc. ├── /src: Folder containing the project's source code │ ├── /baseRuntime.ts: Babylon.js engine creation and rendering loop setup code │ ├── /index.html: HTML template │ ├── /index.ts: Entry point, creates scene using scene builder and starts rendering loop │ └── /sceneBuilder.ts: Code that configures the Scene ``` -------------------------------- ### Register Audio Player in MmdRuntime Source: https://noname0310.github.io/babylon-mmd/docs/get-started/load-and-play-audio Attach the audio player to the MmdRuntime before starting the animation to prevent synchronization glitches. ```typescript //... import { MmdRuntime } from "babylon-mmd/esm/Runtime/mmdRuntime"; //... export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { //... const mmdRuntime = new MmdRuntime(scene); mmdRuntime.loggingEnabled = true; mmdRuntime.register(scene); mmdRuntime.setAudioPlayer(audioPlayer); mmdRuntime.playAnimation(); //... } } ``` -------------------------------- ### Load BPMX via Browser File API Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/the-babylon-pmx-format/bpmx-loader Select and load a local BPMX file using the showOpenFilePicker API. ```typescript const [fileHandle] = await window.showOpenFilePicker({ types: [{ description: "BPMX File", accept: { "application/octet-stream": [".bpmx"], }, }], excludeAcceptAllOption: true, multiple: false, }); const file = await fileHandle.getFile(); const assetContainer: AssetContainer = await LoadAssetContainerAsync(file, scene); assetContainer.addAllToScene(); const mmdMesh = assetContainer.meshes[0] as MmdMesh; ``` -------------------------------- ### Create and Play MmdModel Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/mmd-runtime Shows the process of loading a PMX model, creating an MmdModel instance via the runtime, and playing an animation. ```typescript // initialize MmdRuntime const mmdRuntime = new MmdRuntime(scene, null); mmdRuntime.register(scene); // load VMD animation const vmdLoader = new VmdLoader(); const mmdAnimation = await vmdLoader.loadAsync("motion", "path/to/motion.vmd"); // load PMX model const assetContainer = await LoadAssetContainerAsync("path/to/model.pmx", scene) assetContainer.addAllToScene(); const rootMesh = assetContainer.meshes[0] as Mesh; // create MmdModel and set animation const mmdModel = mmdRuntime.createMmdModel(rootMesh); const runtimeAnimation = mmdModel.createRuntimeAnimation(mmdAnimation); mmdModel.setRuntimeAnimation(runtimeAnimation); // play animation mmdRuntime.playAnimation(); ``` -------------------------------- ### Basic BPMX Conversion Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-model-loader/the-babylon-pmx-format/convert-pmx-to-bpmx-format Demonstrates the standard workflow for converting an MmdMesh to BPMX, including setting the material builder to preserve texture buffers. ```typescript const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.deleteTextureBufferAfterLoad = false; // 1 const assetContainer = await LoadAssetContainerAsync( fileOrUrl, scene, { pluginOptions: { mmdmodel: { materialBuilder: materialBuilder, loggingEnabled: true } } } ); const mmdMesh = assetContainer.meshes[0] as MmdMesh; const bpmxConverter = new BpmxConverter(); bpmxConverter.loggingEnabled = true; const arrayBuffer = bpmxConverter.convert(mmdMesh); // 2 assetContainer.dispose(); // 3 ``` -------------------------------- ### Initialize MMD Scene and Runtime Source: https://noname0310.github.io/babylon-mmd/docs/get-started/scene-details Configures the MMD runtime, loads assets, and sets up physics and audio players for an MMD scene. ```typescript shadowGenerator.frustumEdgeFalloff = 0.1; const ground = CreateGround("ground1", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene); ground.receiveShadows = true; const audioPlayer = new StreamAudioPlayer(scene); audioPlayer.source = "res/private_test/motion/メランコリ・ナイト/melancholy_night.mp3"; // show loading screen engine.displayLoadingUI(); const loadingTexts: string[] = []; const updateLoadingText = (updateIndex: number, text: string): void => { loadingTexts[updateIndex] = text; engine.loadingUIText = "



" + loadingTexts.join("

"); }; const vmdLoader = new VmdLoader(scene); vmdLoader.loggingEnabled = true; const [[mmdRuntime, physicsRuntime], mmdAnimation, modelMesh] = await Promise.all([ (async(): Promise<[MmdRuntime, MultiPhysicsRuntime]> => { updateLoadingText(0, "Loading mmd runtime..."); const wasmInstance = await GetMmdWasmInstance(new MmdWasmInstanceTypeMPR()); updateLoadingText(0, "Loading mmd runtime... Done"); const physicsRuntime = new MultiPhysicsRuntime(wasmInstance); physicsRuntime.setGravity(new Vector3(0, -98, 0)); physicsRuntime.register(scene); const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime)); mmdRuntime.loggingEnabled = true; mmdRuntime.register(scene); mmdRuntime.setAudioPlayer(audioPlayer); mmdRuntime.playAnimation(); return [mmdRuntime, physicsRuntime]; })(), vmdLoader.loadAsync("motion", [ "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_カメラ.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_表情モーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_リップモーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト.vmd" ], (event) => updateLoadingText(0, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)), LoadAssetContainerAsync( "res/private_test/model/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene, { onProgress: (event) => updateLoadingText(1, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), pluginOptions: { mmdmodel: { loggingEnabled: true, materialBuilder: materialBuilder } } } ).then(result => { result.addAllToScene(); return result.rootNodes[0] as MmdMesh; }) ]); scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); const mmdPlayerControl = new MmdPlayerControl(scene, mmdRuntime, audioPlayer); mmdPlayerControl.showPlayerControl(); const cameraAnimationHandle = mmdCamera.createRuntimeAnimation(mmdAnimation); mmdCamera.setRuntimeAnimation(cameraAnimationHandle); mmdRuntime.addAnimatable(mmdCamera); { for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); const mmdModel = mmdRuntime.createMmdModel(modelMesh); const modelAnimationHandle = mmdModel.createRuntimeAnimation(mmdAnimation); mmdModel.setRuntimeAnimation(modelAnimationHandle); } const info = new RigidBodyConstructionInfo(physicsRuntime.wasmInstance); info.motionType = MotionType.Static; info.shape = new PhysicsStaticPlaneShape(physicsRuntime, new Vector3(0, 1, 0), 0); const groundBody = new RigidBody(physicsRuntime, info); physicsRuntime.addRigidBodyToGlobal(groundBody); return scene; } } ``` -------------------------------- ### Control Loading UI Visibility Source: https://noname0310.github.io/babylon-mmd/docs/get-started/scene-details Display the loading UI at the start of the build process and hide it once the first scene render is complete. ```typescript //... export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { engine.displayLoadingUI(); const vmdLoader = new VmdLoader(scene); vmdLoader.loggingEnabled = true; const [[mmdRuntime, physicsRuntime], mmdAnimation, modelMesh] = await Promise.all([ //... ]); scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); //... } } ``` -------------------------------- ### Create Stream Audio Player and MMD Runtime Source: https://noname0310.github.io/babylon-mmd/docs/get-started/load-and-play-audio Initializes the audio player source, registers the MMD runtime, and loads animation and model assets to synchronize playback. ```typescript audioPlayer.source = "res/private_test/motion/メランコリ・ナイト/melancholy_night.mp3"; const vmdLoader = new VmdLoader(scene); vmdLoader.loggingEnabled = true; const mmdRuntime = new MmdRuntime(scene); mmdRuntime.loggingEnabled = true; mmdRuntime.register(scene); mmdRuntime.setAudioPlayer(audioPlayer); mmdRuntime.playAnimation(); const [mmdAnimation, modelMesh] = await Promise.all([ vmdLoader.loadAsync("motion", [ "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_カメラ.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_表情モーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_リップモーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト.vmd" ]), LoadAssetContainerAsync( "res/private_test/model/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene, { pluginOptions: { mmdmodel: { loggingEnabled: true, materialBuilder: materialBuilder } } } ).then(result => { result.addAllToScene(); return result.rootNodes[0] as MmdMesh; }) ]); const cameraAnimationHandle = mmdCamera.createRuntimeAnimation(mmdAnimation); mmdCamera.setRuntimeAnimation(cameraAnimationHandle); mmdRuntime.addAnimatable(mmdCamera); { for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); const mmdModel = mmdRuntime.createMmdModel(modelMesh); const modelAnimationHandle = mmdModel.createRuntimeAnimation(mmdAnimation); mmdModel.setRuntimeAnimation(modelAnimationHandle); } return scene; } } ``` -------------------------------- ### Initialize MMD Physics and Animation Runtime Source: https://noname0310.github.io/babylon-mmd/docs/get-started/add-physics Configures the physics engine, loads MMD assets, and attaches animations to the runtime. ```typescript shadowGenerator.filteringQuality = ShadowGenerator.QUALITY_MEDIUM; shadowGenerator.frustumEdgeFalloff = 0.1; const ground = CreateGround("ground1", { width: 100, height: 100, subdivisions: 2, updatable: false }, scene); ground.receiveShadows = true; const audioPlayer = new StreamAudioPlayer(scene); audioPlayer.source = "res/private_test/motion/メランコリ・ナイト/melancholy_night.mp3"; const vmdLoader = new VmdLoader(scene); vmdLoader.loggingEnabled = true; const [[mmdRuntime, physicsRuntime], mmdAnimation, modelMesh] = await Promise.all([ (async(): Promise<[MmdRuntime, MultiPhysicsRuntime]> => { const wasmInstance = await GetMmdWasmInstance(new MmdWasmInstanceTypeMPR()); const physicsRuntime = new MultiPhysicsRuntime(wasmInstance); physicsRuntime.setGravity(new Vector3(0, -98, 0)); physicsRuntime.register(scene); const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime)); mmdRuntime.loggingEnabled = true; mmdRuntime.register(scene); mmdRuntime.setAudioPlayer(audioPlayer); mmdRuntime.playAnimation(); return [mmdRuntime, physicsRuntime]; })(), vmdLoader.loadAsync("motion", [ "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_カメラ.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_表情モーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト_リップモーション.vmd", "res/private_test/motion/メランコリ・ナイト/メランコリ・ナイト.vmd" ]), LoadAssetContainerAsync( "res/private_test/model/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene, { pluginOptions: { mmdmodel: { loggingEnabled: true, materialBuilder: materialBuilder } } } ).then(result => { result.addAllToScene(); return result.rootNodes[0] as MmdMesh; }) ]); const cameraAnimationHandle = mmdCamera.createRuntimeAnimation(mmdAnimation); mmdCamera.setRuntimeAnimation(cameraAnimationHandle); mmdRuntime.addAnimatable(mmdCamera); { for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); const mmdModel = mmdRuntime.createMmdModel(modelMesh); const modelAnimationHandle = mmdModel.createRuntimeAnimation(mmdAnimation); mmdModel.setRuntimeAnimation(modelAnimationHandle); } const info = new RigidBodyConstructionInfo(physicsRuntime.wasmInstance); info.motionType = MotionType.Static; info.shape = new PhysicsStaticPlaneShape(physicsRuntime, new Vector3(0, 1, 0), 0); const groundBody = new RigidBody(physicsRuntime, info); physicsRuntime.addRigidBodyToGlobal(groundBody); return scene; } } ``` -------------------------------- ### Adjusting Humanoid Model to A-pose Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/apply-mmd-animation-on-non-mmd-model Example of modifying the rotation of upper arm bones to achieve an A-pose, which is required for correct MMD animation binding. ```typescript const modelMesh = modelLoadResult.meshes[1] as Mesh; { const transformNodes = modelLoadResult.transformNodes; const leftArm = transformNodes.find((transformNode) => transformNode.name === "LeftUpperArm")!; const rightArm = transformNodes.find((transformNode) => transformNode.name === "RightUpperArm")!; const degToRad = Math.PI / 180; leftArm.rotationQuaternion = leftArm.rotationQuaternion!.multiply(Quaternion.FromEulerAngles(0, 0, -35 * degToRad)); rightArm.rotationQuaternion = rightArm.rotationQuaternion!.multiply(Quaternion.FromEulerAngles(0, 0, 35 * degToRad)); } ``` -------------------------------- ### Initialize MmdPlayerControl Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/animation/mmd-player-control Instantiate the player control by providing the scene, MMD runtime, and an optional audio player. ```javascript const playerControl = new MmdPlayerControl(scene, mmdRuntime, audioPlayer); ``` -------------------------------- ### Register MmdCamera to MmdRuntime Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/mmd-runtime Demonstrates initializing the runtime, loading a VMD animation, and attaching an MmdCamera to the runtime for playback. ```typescript // initialize MmdRuntime const mmdRuntime = new MmdRuntime(scene, null); mmdRuntime.register(scene); // load VMD animation const vmdLoader = new VmdLoader(); const mmdAnimation = await vmdLoader.loadAsync("motion", "path/to/motion.vmd"); // create MmdCamera and set animation const camera = new MmdCamera(); const runtimeAnimation = camera.createRuntimeAnimation(mmdAnimation); camera.setRuntimeAnimation(runtimeAnimation); // add MmdCamera to MmdRuntime and play animation mmdRuntime.addAnimatable(camera); mmdRuntime.playAnimation(); ``` -------------------------------- ### Create Stream Audio Player Source: https://noname0310.github.io/babylon-mmd/docs/get-started/load-and-play-audio Initialize a StreamAudioPlayer instance and assign the path to your MP3 file. ```typescript import { StreamAudioPlayer } from "babylon-mmd/esm/Runtime/Audio/streamAudioPlayer"; //... export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise { //... const audioPlayer = new StreamAudioPlayer(scene); audioPlayer.source = "res/private_test/motion/メランコリ・ナイト/melancholy_night.mp3"; //... } } ``` -------------------------------- ### Configure MultiPhysicsRuntime Source: https://noname0310.github.io/babylon-mmd/docs/reference/runtime/apply-physics-to-mmd-models Sets up the physics runtime by defining gravity and registering it with the Babylon.js scene. ```typescript const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance); physicsRuntime.setGravity(new Vector3(0, -9.8 * 10, 0)); physicsRuntime.register(scene); ``` -------------------------------- ### Configure MMD Runtime and Physics Source: https://noname0310.github.io/babylon-mmd/docs/reference/overview Initializes the MMD runtime, physics engine, and audio player for synchronized animation playback. ```typescript const mmdWasmInstance = await GetMmdWasmInstance(new MmdWasmInstanceTypeSPR()); const physicsRuntime = new MultiPhysicsRuntime(mmdWasmInstance); physicsRuntime.setGravity(new Vector3(0, -98, 0)); physicsRuntime.register(scene); // MMD runtime for solving morph, append transform, IK, animation, physics const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime)); mmdRuntime.register(scene); // For synced audio playback const audioPlayer = new StreamAudioPlayer(scene); audioPlayer.source = "your_audio_path.mp3"; mmdRuntime.setAudioPlayer(audioPlayer); // You can also run the animation before it loads. This will allow the audio to run first. mmdRuntime.playAnimation(); ``` -------------------------------- ### Configure MMD Runtime Components Source: https://noname0310.github.io/babylon-mmd/docs/reference/overview Sets up the MMD runtime with physics and audio player for synchronized playback. ```typescript // MMD runtime for solving morph, append transform, IK, animation, physics const mmdRuntime = new MmdRuntime(scene, new MmdBulletPhysics(physicsRuntime)); mmdRuntime.register(scene); // For synced audio playback const audioPlayer = new StreamAudioPlayer(scene); audioPlayer.source = "your_audio_path.mp3"; mmdRuntime.setAudioPlayer(audioPlayer); // You can also run the animation before it loads. This will allow the audio to run first. mmdRuntime.playAnimation(); ``` -------------------------------- ### Clone the project template Source: https://noname0310.github.io/babylon-mmd/docs/get-started/project-setup Use this command to clone the base webpack-based project template. ```bash git clone https://github.com/noname0310/babylon-mmd-template ``` -------------------------------- ### Load from VpdObject Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-animation-loader Manual parsing of a VPD file using VpdReader followed by loading into an MmdAnimation. ```typescript const arrayBuffer = await fetch("path/to/pose1.vpd") .then(response => response.arrayBuffer()); const textDecoder = new TextDecoder("shift_jis"); const text = textDecoder.decode(arrayBuffer); const vpdObject = VpdReader.Parse(text); const vpdLoader = new VpdLoader(); const mmdAnimation = await vpdLoader.loadFromVpdObjectAsync("pose1", vpdObject); ``` -------------------------------- ### VpdLoader.loadAsync Source: https://noname0310.github.io/babylon-mmd/docs/reference/loader/mmd-animation-loader Loads a VPD file from a given URL asynchronously and returns an MmdAnimation object. ```APIDOC ## VpdLoader.loadAsync(name: string, url: string) ### Description Loads a VPD file from the specified URL and returns an MmdAnimation representing the pose. ### Parameters - **name** (string) - Required - The name identifier for the animation. - **url** (string) - Required - The path to the .vpd file. ### Returns - **Promise** - A promise that resolves to the loaded animation. ```