2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BabylonJS デカールメッシュによるデカールの実現

Last updated at Posted at 2023-12-13

デカールメッシュ

BabylonJS ではデカールの実現方法について2つの方法が紹介されていますが今回はデカールメッシュで実現する方法を紹介します。CreateDecal を使用します。

デカールメッシュのメッシュの決まり方はざっくりと以下のようになります。

  • position, size, normal, angle の各オプションパラメータに従って1つの直方体を空間に配置する。
  • 直方体の元々のZ軸負の面とZ軸正の面からそれぞれ反対側の面へ向かって平行移動させていく。
  • 平行移動の過程でひっかかったデカール適用先メッシュに沿うようにメッシュを決定していく。

position オプションはデカールメッシュを決定するために配置する直方体の中心位置を指定します。デフォルトは (0, 0, 0) です。
size オプションは直方体のサイズを指定します。デフォルトは (1, 1, 1) です。
normal オプションは直方体のZ軸負面をどちらに向かせるかを指定します。デフォルトは Vector3.Up です。
angle オプションは normal まわりにどれだけねじるかをラジアン単位で指定します。デフォルトは 0 です。
cullBackFaces は直方体のZ軸正の面から平行移動して張るメッシュを無効化するかどうかを指定します。true を指定するとZ軸正の面から張られるメッシュが無効化され、Z軸負の面からだけのメッシュだけになります。デフォルトは false です。

生成したメッシュデカールをそのまま表示すると適用先メッシュとの奥行の関係でちらつきが出てしまうため,Material.zOffset = -2 のようにオフセットを掛けてあげると良いようです。

以下のコードは2023年12月9日の BabylonJS Playground 6.33.1 Javascript で動作したことがあります。

const createScene = async () => {
    const scene = new BABYLON.Scene(engine);
    const camera = new BABYLON.ArcRotateCamera('camera1',
        Math.PI * -60 / 180, Math.PI * 60 / 180, 20,
        new BABYLON.Vector3(4, 0, 0), scene);
    camera.wheelDeltaPercentage = 0.01;
    camera.attachControl(true);

    const light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);
    light.intensity = 0.7;

// 張りつけられるメッシュを作成する
    const b = 0.5;
    const hw = 2;
    const hh = 3;
    const shape = [
        [-hw+b, hh, 0],
        [-hw, hh-b, 0],
        [-hw, -hh+b, 0],
        [-hw+b, -hh, 0]
    ];
    for (let i = 0; i <= 16; ++i) {
        const ang = i * Math.PI / 16;
        const s = Math.sin(ang);
        shape.push([hw * s, -hh * Math.cos(ang), 0]);
    }

    const path = [];
    for (let i = 0; i <= 10; ++i) {
        path.push([i, 0, 0]);
    }

    const opt = {
        shape: shape.map(p => new BABYLON.Vector3(...p)),
        closeShape: true,
        path: path.map(p => new BABYLON.Vector3(...p)),
        cap: BABYLON.Mesh.CAP_ALL,
        rotationFunction: (i, distance) => {
            return Math.PI * 90 / 180 / 10;
        },
    };
    const mesh = BABYLON.MeshBuilder.ExtrudeShapeCustom('mesh1', opt, scene);
    scene.onBeforeRenderObservable.add((scene) => {
        mesh.rotate(new BABYLON.Vector3(1, 0, 0), 0.008);
    });

// デカールメッシュを生成する
    const decalOpt = {
        position: new BABYLON.Vector3(5, 0, 0),
        normal: new BABYLON.Vector3(0, 1, -1).normalize(),
        size: new BABYLON.Vector3(6, 6, 10),
        angle: Math.PI * 20 / 180,
        localMode: true,
        cullBackFaces: true,
    };
    const meshDecal = BABYLON.MeshBuilder.CreateDecal('decal1',
        mesh, decalOpt);

// テクスチャの生成と描画
    const texOpt = { width: 512, height: 512 };
    const tex = new BABYLON.DynamicTexture('tex1', texOpt, scene);
    tex.hasAlpha = true;
    const c = tex.getContext();
    c.fillStyle = 'rgba(255, 153, 0, 1)';
    const w = c.canvas.width;
    const h = c.canvas.height;
    c.fillRect(0, h/4, w, h/2);
    c.fillStyle = 'red';
    c.textAlign = 'center';
    c.textBaseline = 'middle';
    c.font = 'bold 120px Ariel';
    c.fillText('babylon', w / 2, h / 2);
    tex.update();

    const material = new BABYLON.StandardMaterial('material1', scene);
    material.zOffset = -2; // ちらつき防止
    material.diffuseTexture = tex;
    meshDecal.material = material;

    return scene;
};
実行結果1
dm1.png
曲面に張りつけた表現になりました
実行結果2
dm2.png
デカールメッシュをワイヤーフレーム表示した状態

リンク

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?