Babylon.js - Morph Targets demo source

Back to demo

main.ts

import { runDemo } from "../shared/demoRunner";
import { createMorphTargetsTestScene } from "./scene";

runDemo({ createScene: createMorphTargetsTestScene });

scene.ts

import type { Engine } from "@babylonjs/core/Engines/engine";
import { Scene } from "@babylonjs/core/scene";
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera";
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight";
import { PBRMaterial } from "@babylonjs/core/Materials/PBR/pbrMaterial";
import { HDRCubeTexture } from "@babylonjs/core/Materials/Textures/hdrCubeTexture";
import { Color3 } from "@babylonjs/core/Maths/math.color";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder";
import { VertexBuffer } from "@babylonjs/core/Buffers/buffer";
import { VertexData } from "@babylonjs/core/Meshes/mesh.vertexData";
import { MorphTargetManager } from "@babylonjs/core/Morph/morphTargetManager";
import { MorphTarget } from "@babylonjs/core/Morph/morphTarget";
import type { Mesh } from "@babylonjs/core/Meshes/mesh";

function addSpike(mesh: Mesh): void {
    const positions = mesh.getVerticesData(VertexBuffer.PositionKind)!;
    const normals = mesh.getVerticesData(VertexBuffer.NormalKind)!;
    const indices = mesh.getIndices()!;

    for (let index = 0; index < 5; index++) {
        const randomVertexID = (mesh.getTotalVertices() * Math.random()) | 0;
        const position = Vector3.FromArray(positions, randomVertexID * 3);
        const normal = Vector3.FromArray(normals, randomVertexID * 3);

        position.addInPlace(normal);
        position.toArray(positions, randomVertexID * 3);
    }

    VertexData.ComputeNormals(positions, indices, normals);
    mesh.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
    mesh.updateVerticesData(VertexBuffer.NormalKind, normals, false, false);
}

export function createMorphTargetsTestScene(engine: Engine, canvas: HTMLCanvasElement): Scene {
    const scene = new Scene(engine);

    const camera = new ArcRotateCamera("camera1", 1.14, 1.13, 10, Vector3.Zero(), scene);
    camera.setTarget(Vector3.Zero());
    camera.attachControl(canvas, true);

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

    const sphere = CreateSphere("sphere1", { segments: 16, diameter: 2 }, scene);

    const hdrTexture = new HDRCubeTexture("/Demos/Highlights/room.hdr", scene, 512);

    const glass = new PBRMaterial("glass", scene);
    glass.reflectionTexture = hdrTexture;
    glass.refractionTexture = hdrTexture;
    glass.linkRefractionWithTransparency = true;
    glass.indexOfRefraction = 0.52;
    glass.alpha = 0;
    glass.microSurface = 1;
    glass.reflectivityColor = new Color3(0.2, 0.2, 0.2);
    glass.albedoColor = new Color3(0.85, 0.85, 0.85);
    sphere.material = glass;

    const sphere2 = CreateSphere("sphere2", { segments: 16, diameter: 2 }, scene);
    sphere2.setEnabled(false);
    addSpike(sphere2);

    const sphere3 = CreateSphere("sphere3", { segments: 16, diameter: 2 }, scene);
    sphere3.setEnabled(false);
    addSpike(sphere3);

    const sphere4 = CreateSphere("sphere4", { segments: 16, diameter: 2 }, scene);
    sphere4.setEnabled(false);
    addSpike(sphere4);

    const sphere5 = CreateSphere("sphere5", { segments: 16, diameter: 2 }, scene);
    sphere5.setEnabled(false);
    addSpike(sphere5);

    const manager = new MorphTargetManager();
    sphere.morphTargetManager = manager;

    const target0 = MorphTarget.FromMesh(sphere2, "sphere2", 0.25);
    manager.addTarget(target0);

    const target1 = MorphTarget.FromMesh(sphere3, "sphere3", 0.25);
    manager.addTarget(target1);

    const target2 = MorphTarget.FromMesh(sphere4, "sphere4", 0.25);
    manager.addTarget(target2);

    const target3 = MorphTarget.FromMesh(sphere5, "sphere5", 0.25);
    manager.addTarget(target3);

    let t = 0;
    scene.registerBeforeRender(function () {
        t += 0.02;
        target0.influence = Math.sin(t) * 0.5 + 0.5;
        target1.influence = Math.sin(t * 1.3) * 0.5 + 0.5;
        target2.influence = Math.sin(t * 0.7) * 0.5 + 0.5;
        target3.influence = Math.sin(t * 1.7) * 0.5 + 0.5;
    });

    return scene;
}