メインコンテンツまでスキップ

基本的なシーンの作成

ここでは基本的なシーンを作成します。以下の要素を追加します:

  • カメラの作成: シーンを見るためのビューポイントを提供します。
  • 背景とアンビエントカラーの設定: シーンの ClearColorAmbientColor を設定します。
  • ライティングの追加: モデルがはっきりと見えるようにシーンを照らします。
  • グラウンドの作成: モデルが立つための床を作成します。

カメラの作成

まず、カメラを作成しましょう。

レンダラーが正しく機能するためには、activeCamera として設定されたカメラが必要です。

src/sceneBuilder.ts
//...
import { MmdCamera } from "babylon-mmd/esm/Runtime/mmdCamera";

import type { ISceneBuilder } from "./baseRuntime";

export class SceneBuilder implements ISceneBuilder {
public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise<Scene> {
const scene = new Scene(engine);

const mmdCamera = new MmdCamera("MmdCamera", new Vector3(0, 10, 0), scene);

return scene;
}
}

babylon-mmd パッケージが提供する MmdCamera を使用します。

このカメラは、MMD ソフトウェアのカメラの動作を再現します。

背景とアンビエントカラーの設定

背景色アンビエントライティングを設定します。背景色は ClearColor で、アンビエントライティングは AmbientColor で設定できます。

src/sceneBuilder.ts
//...
import { Color3, Color4 } from "@babylonjs/core/Maths/math.color";
//...
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
//...

export class SceneBuilder implements ISceneBuilder {
public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise<Scene> {
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);

return scene;
}
}

ここで、scene.ambientColor はすべてのマーテリアルの ambientColor プロパティに影響します。

MMD モデルの場合、シェーディングを適切に再現するために ambientColor に 0.5 のスケーリングを適用する必要があるため、この (0.5, 0.5, 0.5) の値は意図的なものであり、任意ではありません。

ライトの作成

MMD のライティングモデルは、単一のディレクショナルライトによって定義されます。

したがって、他のライティング設定では正しくレンダリングされない場合があります。たとえば、ヘミスフェリックライトを一緒に使用すると、MMD ソフトウェアとは異なるシェーディング結果が生成される可能性があります。

DirectionalLight を作成し、シャドウをレンダリングするために ShadowGenerator も作成します。

src/sceneBuilder.ts
import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent";
//...

import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
//...
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
//...
export class SceneBuilder implements ISceneBuilder {
public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise<Scene> {
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;
return scene;
}
}

ShadowGenerator の設定は任意の値であり、必要に応じて調整できます。

グラウンドの作成

グラウンドプレーンを作成します。これはシーンを視覚的に理解するのに役立ちますが、必須ではありません

src/sceneBuilder.ts
//...
import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder";
//...
export class SceneBuilder implements ISceneBuilder {
public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise<Scene> {
const scene = new Scene(engine);

// ...

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;
}
}

結果

シーンを実行すると、エラーが発生しなくなり、次のような白い画面が表示されるはずです:

result

完全なコード
src/sceneBuilder.ts
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";

import type { ISceneBuilder } from "./baseRuntime";

export class SceneBuilder implements ISceneBuilder {
public async build(_canvas: HTMLCanvasElement, engine: AbstractEngine): Promise<Scene> {
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;
}
}