From b2bd9426080d7a1fc58f1008467835677ebd8f23 Mon Sep 17 00:00:00 2001 From: noname0310 Date: Wed, 4 Sep 2024 21:47:42 +0900 Subject: [PATCH] update document example code --- .../0-quick-start/1-load-mmd-model/index.md | 17 ++- .../index.md | 76 +++++++--- .../1-deep-usage/2-load-bpmx-model/index.md | 143 ++++++++++-------- .../5-load-bvmd-animation/index.mdx | 94 ++++++------ .../index.md | 2 +- .../1-deep-usage/9-multiple-cameras/index.md | 85 ++++++----- 6 files changed, 234 insertions(+), 183 deletions(-) diff --git a/docs/docs/0-quick-start/1-load-mmd-model/index.md b/docs/docs/0-quick-start/1-load-mmd-model/index.md index 82622d9f..abecb3e3 100644 --- a/docs/docs/0-quick-start/1-load-mmd-model/index.md +++ b/docs/docs/0-quick-start/1-load-mmd-model/index.md @@ -26,22 +26,23 @@ For load pmx model, we need to import side effects. import "babylon-mmd/esm/Loader/pmxLoader"; ``` -Then, load the model using the `SceneLoader`. +Then, load the model using the `loadAssetContainerAsync`. ```typescript title="src/sceneBuilder.ts" -const mmdMesh = await SceneLoader.ImportMeshAsync("", "res/YYB Hatsune Miku_10th/", "YYB Hatsune Miku_10th_v1.02.pmx", scene) - .then((result) => result.meshes[0] as MmdMesh); +const mmdMesh = await loadAssetContainerAsync("res/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene) + .then((result) => { + result.addAllToScene(); + return result.meshes[0] as MmdMesh; + }); for (const mesh of mmdMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(mmdMesh); ``` -- `SceneLoader.ImportMeshAsync` - Load the model using the `SceneLoader` (All other loading methods are supported, but this example uses `ImportMeshAsync`). - - `""` - this parameter is not used in PMX loading. - - `"res/YYB Hatsune Miku_10th/"` - the path to the model file. - - `"YYB Hatsune Miku_10th_v1.02.pmx"` - If you pass a File object, you can load the model from the File object. +- `loadAssetContainerAsync` - Load the model (All other loading methods like `SceneLoader.ImportMeshAsync` are also supported). + - `"res/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx"` - the path to the model file. If you pass a File object, you can load the model from the File object. - `scene` - the scene to load the model into. -- An importMeshAsync call in pmx file guarantees that result.meshes length is always greater than 0 and result.meshes[0] is always a root mesh which type is MmdMesh. +- An loadAssetContainerAsync call in pmx file guarantees that result.meshes length is always greater than 0 and result.meshes[0] is always a root mesh which type is MmdMesh. - Below is the shadow setting I won't explain in detail. diff --git a/docs/docs/0-quick-start/5-troubleshooting-shading-artifacts/index.md b/docs/docs/0-quick-start/5-troubleshooting-shading-artifacts/index.md index b4471581..bb8bf97f 100644 --- a/docs/docs/0-quick-start/5-troubleshooting-shading-artifacts/index.md +++ b/docs/docs/0-quick-start/5-troubleshooting-shading-artifacts/index.md @@ -22,8 +22,13 @@ SdefInjector.OverrideEngineCreateEffect(engine); // Force all shaders to support or ```typescript title="src/sceneBuilder.ts" -const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; -pmxLoader.useSdef = false; // Disable SDEF +const assetContainer = await loadAssetContainerAsync("res/your_model.pmx", scene, { + pluginOptions: { // you can pass options to the loader using pluginOptions + mmdmodel: { + useSdef: false // Disable SDEF + } + } +}); ``` Result: @@ -54,25 +59,37 @@ The proper `transparencyMode` of the mesh is determined at load time by a specif To fix this, you can disable the optimization settings. The code looks like this: ```typescript -const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; -const materialBuilder = pmxLoader.materialBuilder as MmdStandardMaterialBuilder; +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.renderMethod = MmdStandardMaterialRenderMethod.DepthWriteAlphaBlending; + +const assetContainer = await loadAssetContainerAsync("res/your_model.pmx", scene, { + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder // Override the material builder + } + } +}); ``` The other approach is to choose the most appropriate `transparencyMode` possible without using `forceDepthWrite`. This approach should be compatible with most post-processing and shaders. ```typescript -const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; -const materialBuilder = pmxLoader.materialBuilder as MmdStandardMaterialBuilder; +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.renderMethod = MmdStandardMaterialRenderMethod.AlphaEvaluation; + +const assetContainer = await loadAssetContainerAsync("res/your_model.pmx", scene, { + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder // Override the material builder + } + } +}); ``` The `DepthWriteAlphaBlendingWithEvaluation` and `AlphaEvaluation` methods both add some delays to the execution of the algorithm. To improve this, you can force off the optimization that automatically determines the `transparencyMode` and set the `transparencyMode` manually. ```typescript -const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; -pmxLoader.useSdef = false; -const materialBuilder = pmxLoader.materialBuilder as MmdStandardMaterialBuilder; +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.forceDisableAlphaEvaluation = true; const alphaBlendMaterials = ["face02", "Facial02", "HL", "Hairshadow", "q302"]; const alphaTestMaterials = ["q301"]; @@ -84,6 +101,14 @@ materialBuilder.afterBuildSingleMaterial = (material): void => { material.useAlphaFromDiffuseTexture = true; material.diffuseTexture!.hasAlpha = true; }; + +const assetContainer = await loadAssetContainerAsync("res/your_model.pmx", scene, { + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder // Override the material builder + } + } +}); ``` - `forceDisableAlphaEvaluation` - If true, the optimization that automatically determines the `transparencyMode` is disabled. @@ -96,10 +121,16 @@ Outline rendering might looks weird with some post-processes or shaders. In this case, you should consider turning off outline rendering partially or disabling it in loaders. ```typescript title="src/sceneBuilder.ts" -const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; -const materialBuilder = pmxLoader.materialBuilder as MmdStandardMaterialBuilder; - +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.loadOutlineRenderingProperties = () => { /* do nothing */ }; + +const assetContainer = await loadAssetContainerAsync("res/your_model.pmx", scene, { + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder // Override the material builder + } + } +}); ``` - `loadOutlineRenderingProperties` - This callback is called when loading the outline rendering properties. You can override this to customize the outline rendering properties. @@ -114,21 +145,18 @@ So if you want to make any changes to the loaded asset, check the loader option ```typescript title="src/sceneBuilder.ts" import type { Engine } from "@babylonjs/core"; -import { Color3, DirectionalLight, HavokPlugin, HemisphericLight, Material, MeshBuilder, Scene, SceneLoader, ShadowGenerator, Vector3 } from "@babylonjs/core"; +import { Color3, DirectionalLight, HavokPlugin, HemisphericLight, Material, MeshBuilder, Scene, ShadowGenerator, Vector3 } from "@babylonjs/core"; import HavokPhysics from "@babylonjs/havok"; -import type { MmdStandardMaterialBuilder } from "babylon-mmd"; -import { MmdCamera, MmdMesh, MmdPhysics, MmdPlayerControl, MmdRuntime, PmxLoader, SdefInjector, StreamAudioPlayer, VmdLoader } from "babylon-mmd"; +import { MmdCamera, MmdMesh, MmdPhysics, MmdPlayerControl, MmdRuntime, MmdStandardMaterialBuilder, PmxLoader, SdefInjector, StreamAudioPlayer, VmdLoader } from "babylon-mmd"; import type { ISceneBuilder } from "./baseRuntime"; export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: Engine): Promise { SdefInjector.OverrideEngineCreateEffect(engine); - SceneLoader.RegisterPlugin(new PmxLoader()); // fix material alpha mode - const pmxLoader = SceneLoader.GetPluginForExtension(".pmx") as PmxLoader; - const materialBuilder = pmxLoader.materialBuilder as MmdStandardMaterialBuilder; + const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.useAlphaEvaluation = false; const alphaBlendMaterials = ["face02", "Facial02", "HL", "Hairshadow", "q302"]; const alphaTestMaterials = ["q301"]; @@ -165,8 +193,16 @@ export class SceneBuilder implements ISceneBuilder { shadowGenerator.addShadowCaster(ground); // load mmd model - const mmdMesh = await SceneLoader.ImportMeshAsync("", "res/YYB Hatsune Miku_10th/", "YYB Hatsune Miku_10th_v1.02.pmx", scene) - .then((result) => result.meshes[0] as MmdMesh); + const mmdMesh = await loadAssetContainerAsync("res/YYB Hatsune Miku_10th/YYB Hatsune Miku_10th_v1.02.pmx", scene, { + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder + } + } + }).then((result) => { + result.addAllToScene(); + return result.meshes[0] as MmdMesh; + }); for (const mesh of mmdMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(mmdMesh); diff --git a/docs/docs/1-deep-usage/2-load-bpmx-model/index.md b/docs/docs/1-deep-usage/2-load-bpmx-model/index.md index b19767a7..2794f5b3 100644 --- a/docs/docs/1-deep-usage/2-load-bpmx-model/index.md +++ b/docs/docs/1-deep-usage/2-load-bpmx-model/index.md @@ -21,52 +21,51 @@ import "@babylonjs/core/Materials/Textures/Loaders/tgaTextureLoader"; ``` ::: -Then, load the model using the `SceneLoader`. +Then, load the model using the `loadAssetContainerAsync`. ```typescript title="src/sceneBuilder.ts" -const bpmxLoader = SceneLoader.GetPluginForExtension(".bpmx") as BpmxLoader; -bpmxLoader.loggingEnabled = true; -const materialBuilder = bpmxLoader.materialBuilder as MmdStandardMaterialBuilder; +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ }; engine.displayLoadingUI(); -bpmxLoader.boundingBoxMargin = 60; -const modelMesh = await SceneLoader.ImportMeshAsync( - undefined, - "res/", - "YYB Piano dress Miku.bpmx", +const modelMesh = await loadAssetContainerAsync( + "res/YYB Piano dress Miku.bpmx", scene, - (event) => engine.loadingUIText = `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)` -).then((result) => result.meshes[0] as MmdMesh); + { + onProgress: (event) => engine.loadingUIText = `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`, + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + boundingBoxMargin: 60, + loggingEnabled: true + } + } + } +).then((result) => { + result.addAllToScene(); + return result.meshes[0] as MmdMesh; +}); modelMesh; scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); ``` -- `SceneLoader.GetPluginForExtension(".bpmx")` - Get the `BpmxLoader` from the `SceneLoader`. - -- `bpmxLoader.loggingEnabled = true;` - Enable logging for better debugging. +- `materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ };` - Override the method to disable outline rendering. (This is just a setting for the goal in this example.) -- `bpmxLoader.materialBuilder` - In this case we get the `MmdStandardMaterialBuilder` from the `BpmxLoader`. If you implement your own material builder, you can pass it to the loader. +- `materialBuilder: materialBuilder` - In this case we instantiate and pass the `MmdStandardMaterialBuilder`, but you can also implement your own material builder and pass it. -- `materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ };` - Override the method to disable outline rendering. (This is just a setting for the goal in this example.) +- `boundingBoxMargin: 60` - Set the bounding box margin. (The default value is 10.) -- `bpmxLoader.boundingBoxMargin = 60;` - Set the bounding box margin. (The default value is 10.) +- `loggingEnabled: true` - Enable logging for better debugging. (The default value is false.) :::info -Basically, dance motion can cause curring problem because it moves mesh a lot from rest pose. +Basically, dance motion can cause curring problem because it moves mesh far from the bounding box. And the motion that we're going to use in this next example is especially problematic, so we need to make the bounding box bigger. ::: -:::tip -If you change the settings of the `BpmxLoader` before calling `ImportMeshAsync`, the settings will be applied to the loaded model. - -The reason for using this method is that `ImportMeshAsync` does not have a parameter to pass the load options to the loader. -::: - ![result1](image.png) :::info @@ -79,26 +78,34 @@ You'll see this error message. These errors are often displayed when the 3D mode For models such as Stage, it is usually static. Importing these models into a static mesh can save performance. +If you don't need to get the mesh object, you can use `appendSceneAsync` instead of `loadAssetContainerAsync` which is more simple. + ```typescript title="src/sceneBuilder.ts" -bpmxLoader.boundingBoxMargin = 0; -bpmxLoader.buildSkeleton = false; -bpmxLoader.buildMorph = false; -// promises.push( -await SceneLoader.ImportMeshAsync( - undefined, - "res/", - "ガラス片ドームB.bpmx", +await appendSceneAsync( + "res/ガラス片ドームB.bpmx", scene, - (event) => engine.loadingUIText = `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)` + { + onProgress: (event) => engine.loadingUIText = `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`, + pluginOptions: { + mmdmodel: { + buildSkeleton: false, + buildMorph: false, + boundingBoxMargin: 0, + loggingEnabled: true + } + } + } ); ``` -- `bpmxLoader.boundingBoxMargin = 0;` - Set the bounding box margin to 0. (because static mesh doesn't move) -- `bpmxLoader.buildSkeleton = false;` - Disable building skeleton. -- `bpmxLoader.buildMorph = false;` - Disable building morph. +- `buildSkeleton: false` - Disable building skeleton. + +- `buildMorph: false` - Disable building morph. + +- `boundingBoxMargin: 0` - Set the bounding box margin to 0. (because static mesh doesn't move) :::info -Naturally, mmd models loaded with static mesh cannot be controlled by MMD Runtime. +Naturally, mmd models loaded as static mesh cannot be controlled by MMD Runtime. ::: ![result2](image-1.png) @@ -108,9 +115,6 @@ Naturally, mmd models loaded with static mesh cannot be controlled by MMD Runtim Now, we are awaiting the model and stage to load one by one, but we can load them simultaneously by using `Promise.all`. ```typescript title="src/sceneBuilder.ts" -const bpmxLoader = SceneLoader.GetPluginForExtension(".bpmx") as BpmxLoader; -bpmxLoader.loggingEnabled = true; - engine.displayLoadingUI(); let loadingTexts: string[] = []; @@ -119,34 +123,40 @@ const updateLoadingText = (updateIndex: number, text: string): void => { engine.loadingUIText = "



" + loadingTexts.join("

"); }; -const promises: Promise[] = []; +const [modelMesh, ] = await Promise.all([ + SceneLoader.ImportMeshAsync( + "res/YYB Piano dress Miku.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + boundingBoxMargin: 60, + loggingEnabled: true + } + } + } + ).then((result) => result.meshes[0] as MmdMesh), + SceneLoader.ImportMeshAsync( + "res/ガラス片ドームB.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + buildSkeleton: false, + buildMorph: false, + boundingBoxMargin: 0, + loggingEnabled: true + } + } + } + ) +]); -bpmxLoader.boundingBoxMargin = 60; -promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "YYB Piano dress Miku.bpmx", - scene, - (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) -).then((result) => result.meshes[0])); - -bpmxLoader.boundingBoxMargin = 0; -bpmxLoader.buildSkeleton = false; -bpmxLoader.buildMorph = false; -promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "ガラス片ドームB.bpmx", - scene, - (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) -)); - -loadingTexts = new Array(promises.length).fill(""); - -const loadResults = await Promise.all(promises); scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); - -loadResults; ``` - Simply added `Promise.all` and the loading screen. @@ -154,7 +164,6 @@ loadResults; ## Add Shadow to Model ```typescript title="src/sceneBuilder.ts" -const modelMesh = loadResults[0] as MmdMesh; for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); ``` diff --git a/docs/docs/1-deep-usage/5-load-bvmd-animation/index.mdx b/docs/docs/1-deep-usage/5-load-bvmd-animation/index.mdx index 2ee8b14c..4d4178e1 100644 --- a/docs/docs/1-deep-usage/5-load-bvmd-animation/index.mdx +++ b/docs/docs/1-deep-usage/5-load-bvmd-animation/index.mdx @@ -40,9 +40,8 @@ For load BVMD animation, we use the `BvmdLoader`. const bvmdLoader = new BvmdLoader(scene); bvmdLoader.loggingEnabled = true; -promises.push(bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", - (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)) -); +const mmdAnimation = await bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", + (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)); ``` - `bvmdLoader.loadAsync(name, fileOrUrl, onProgress)` - Load BVMD file. `name` is the name of the animation. `onProgress` is a callback function that is called during loading. @@ -57,10 +56,10 @@ import "babylon-mmd/esm/Runtime/Animation/mmdRuntimeModelAnimation"; Here's how to add and play animations. ```typescript title="src/sceneBuilder.ts" -mmdCamera.addAnimation(loadResults[2]); +mmdCamera.addAnimation(mmdAnimation); mmdCamera.setAnimation("motion_1"); -mmdModel.addAnimation(loadResults[2]); +mmdModel.addAnimation(mmdAnimation); mmdModel.setAnimation("motion_1"); ``` @@ -83,7 +82,7 @@ mmdCamera.parent = mmdRoot; modelMesh.parent = mmdRoot; ``` -## Make Directional Light Follow Model +## Make Directional Light Follow The Model Our shadow frustum is fitted to the model. So we need to move the directional light to follow the model. to see the shadow properly. @@ -125,15 +124,14 @@ import type { Engine } from "@babylonjs/core/Engines/engine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; -import { SceneLoader } from "@babylonjs/core/Loading/sceneLoader"; +import { loadAssetContainerAsync, appendSceneAsync } from "@babylonjs/core/Loading/sceneLoader"; import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; import { Matrix, Vector3 } from "@babylonjs/core/Maths/math.vector"; import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder"; import { TransformNode } from "@babylonjs/core/Meshes/transformNode"; import { Scene } from "@babylonjs/core/scene"; -import type { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; -import type { BpmxLoader } from "babylon-mmd/esm/Loader/Optimized/bpmxLoader"; +import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; import { BvmdLoader } from "babylon-mmd/esm/Loader/Optimized/bvmdLoader"; import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera"; import type { MmdMesh } from "babylon-mmd/esm/Runtime/mmdMesh"; @@ -143,9 +141,7 @@ import type { ISceneBuilder } from "./baseRuntime"; export class SceneBuilder implements ISceneBuilder { public async build(_canvas: HTMLCanvasElement, engine: Engine): Promise { - const bpmxLoader = SceneLoader.GetPluginForExtension(".bpmx") as BpmxLoader; - bpmxLoader.loggingEnabled = true; - const materialBuilder = bpmxLoader.materialBuilder as MmdStandardMaterialBuilder; + const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ }; const scene = new Scene(engine); @@ -203,48 +199,54 @@ export class SceneBuilder implements ISceneBuilder { loadingTexts[updateIndex] = text; engine.loadingUIText = "



" + loadingTexts.join("

"); }; - - const promises: Promise[] = []; - - bpmxLoader.boundingBoxMargin = 60; - promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "YYB Piano dress Miku.bpmx", - scene, - (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) - ).then((result) => result.meshes[0])); - - bpmxLoader.boundingBoxMargin = 0; - bpmxLoader.buildSkeleton = false; - bpmxLoader.buildMorph = false; - promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "ガラス片ドームB.bpmx", - scene, - (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) - )); - + const bvmdLoader = new BvmdLoader(scene); bvmdLoader.loggingEnabled = true; - promises.push(bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", - (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)) - ); + const [modelMesh, , mmdAnimation] = await Promise.all([ + loadAssetContainerAsync( + "res/YYB Piano dress Miku.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + boundingBoxMargin: 60, + loggingEnabled: true + } + } + } + ).then((result) => { + result.addAllToScene(); + return result.meshes[0] as MmdMesh; + }), + appendSceneAsync( + "res/ガラス片ドームB.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + buildSkeleton: false, + buildMorph: false, + boundingBoxMargin: 0, + loggingEnabled: true + } + } + } + ), + bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", + (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)) + ]); - loadingTexts = new Array(promises.length).fill(""); - - const loadResults = await Promise.all(promises); scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); - loadResults; - mmdRuntime.setCamera(mmdCamera); - mmdCamera.addAnimation(loadResults[2]); + mmdCamera.addAnimation(mmdAnimation); mmdCamera.setAnimation("motion_1"); - const modelMesh = loadResults[0] as MmdMesh; modelMesh.parent = mmdRoot; for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); @@ -259,7 +261,7 @@ export class SceneBuilder implements ISceneBuilder { }); const mmdModel = mmdRuntime.createMmdModel(modelMesh); - mmdModel.addAnimation(loadResults[2]); + mmdModel.addAnimation(mmdAnimation); mmdModel.setAnimation("motion_1"); return scene; diff --git a/docs/docs/1-deep-usage/7-troubleshooting-shading-artifacts/index.md b/docs/docs/1-deep-usage/7-troubleshooting-shading-artifacts/index.md index 9a3dea70..70c8ff25 100644 --- a/docs/docs/1-deep-usage/7-troubleshooting-shading-artifacts/index.md +++ b/docs/docs/1-deep-usage/7-troubleshooting-shading-artifacts/index.md @@ -11,6 +11,6 @@ SdefInjector.OverrideEngineCreateEffect(engine); Outline rendering has already been disabled on [Load BPMX Model](../load-bpmx-model/) page. ```typescript title="src/sceneBuilder.ts" -const materialBuilder = bpmxLoader.materialBuilder as MmdStandardMaterialBuilder; +const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ }; ``` diff --git a/docs/docs/1-deep-usage/9-multiple-cameras/index.md b/docs/docs/1-deep-usage/9-multiple-cameras/index.md index c24e6164..b2264180 100644 --- a/docs/docs/1-deep-usage/9-multiple-cameras/index.md +++ b/docs/docs/1-deep-usage/9-multiple-cameras/index.md @@ -112,7 +112,7 @@ import type { Engine } from "@babylonjs/core/Engines/engine"; import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight"; import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"; import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator"; -import { SceneLoader } from "@babylonjs/core/Loading/sceneLoader"; +import { loadAssetContainerAsync, appendSceneAsync } from "@babylonjs/core/Loading/sceneLoader"; import { ImageProcessingConfiguration } from "@babylonjs/core/Materials/imageProcessingConfiguration"; import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial"; import { Color3, Color4 } from "@babylonjs/core/Maths/math.color"; @@ -123,8 +123,7 @@ import { DepthOfFieldEffectBlurLevel } from "@babylonjs/core/PostProcesses/depth import { DefaultRenderingPipeline } from "@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline"; import { SSRRenderingPipeline } from "@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline"; import { Scene } from "@babylonjs/core/scene"; -import type { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; -import type { BpmxLoader } from "babylon-mmd/esm/Loader/Optimized/bpmxLoader"; +import { MmdStandardMaterialBuilder } from "babylon-mmd/esm/Loader/mmdStandardMaterialBuilder"; import { BvmdLoader } from "babylon-mmd/esm/Loader/Optimized/bvmdLoader"; import { SdefInjector } from "babylon-mmd/esm/Loader/sdefInjector"; import { StreamAudioPlayer } from "babylon-mmd/esm/Runtime/Audio/streamAudioPlayer"; @@ -139,9 +138,7 @@ export class SceneBuilder implements ISceneBuilder { public async build(canvas: HTMLCanvasElement, engine: Engine): Promise { SdefInjector.OverrideEngineCreateEffect(engine); - const bpmxLoader = SceneLoader.GetPluginForExtension(".bpmx") as BpmxLoader; - bpmxLoader.loggingEnabled = true; - const materialBuilder = bpmxLoader.materialBuilder as MmdStandardMaterialBuilder; + const materialBuilder = new MmdStandardMaterialBuilder(); materialBuilder.loadOutlineRenderingProperties = (): void => { /* do nothing */ }; const scene = new Scene(engine); @@ -205,7 +202,7 @@ export class SceneBuilder implements ISceneBuilder { audioPlayer.source = "res/pizzicato_drops.mp3"; mmdRuntime.setAudioPlayer(audioPlayer); - // // create player control + // create player control new MmdPlayerControl(scene, mmdRuntime, audioPlayer); engine.displayLoadingUI(); @@ -215,48 +212,54 @@ export class SceneBuilder implements ISceneBuilder { loadingTexts[updateIndex] = text; engine.loadingUIText = "



" + loadingTexts.join("

"); }; - - const promises: Promise[] = []; - - bpmxLoader.boundingBoxMargin = 60; - promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "YYB Piano dress Miku.bpmx", - scene, - (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) - ).then((result) => result.meshes[0])); - - bpmxLoader.boundingBoxMargin = 0; - bpmxLoader.buildSkeleton = false; - bpmxLoader.buildMorph = false; - promises.push(SceneLoader.ImportMeshAsync( - undefined, - "res/", - "ガラス片ドームB.bpmx", - scene, - (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`) - )); - + const bvmdLoader = new BvmdLoader(scene); bvmdLoader.loggingEnabled = true; - promises.push(bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", - (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)) - ); - - loadingTexts = new Array(promises.length).fill(""); + const [modelMesh, , mmdAnimation] = await Promise.all([ + loadAssetContainerAsync( + "res/YYB Piano dress Miku.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(0, `Loading model... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + boundingBoxMargin: 60, + loggingEnabled: true + } + } + } + ).then((result) => { + result.addAllToScene(); + return result.meshes[0] as MmdMesh; + }), + appendSceneAsync( + "res/ガラス片ドームB.bpmx", + scene, + { + onProgress: (event) => updateLoadingText(1, `Loading stage... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`), + pluginOptions: { + mmdmodel: { + materialBuilder: materialBuilder, + buildSkeleton: false, + buildMorph: false, + boundingBoxMargin: 0, + loggingEnabled: true + } + } + } + ), + bvmdLoader.loadAsync("motion_1", "res/pizzicato_drops_yyb_piano_miku.bvmd", + (event) => updateLoadingText(2, `Loading motion... ${event.loaded}/${event.total} (${Math.floor(event.loaded * 100 / event.total)}%)`)) + ]); - const loadResults = await Promise.all(promises); scene.onAfterRenderObservable.addOnce(() => engine.hideLoadingUI()); - loadResults; - mmdRuntime.setCamera(mmdCamera); - mmdCamera.addAnimation(loadResults[2]); + mmdCamera.addAnimation(mmdAnimation); mmdCamera.setAnimation("motion_1"); - const modelMesh = loadResults[0] as MmdMesh; modelMesh.parent = mmdRoot; for (const mesh of modelMesh.metadata.meshes) mesh.receiveShadows = true; shadowGenerator.addShadowCaster(modelMesh); @@ -274,7 +277,7 @@ export class SceneBuilder implements ISceneBuilder { }); const mmdModel = mmdRuntime.createMmdModel(modelMesh); - mmdModel.addAnimation(loadResults[2]); + mmdModel.addAnimation(mmdAnimation); mmdModel.setAnimation("motion_1"); const ssrRenderingPipeline = new SSRRenderingPipeline(