Babylon.js - Shadows demo source

Back to demo

main.ts

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

runDemo({
    createScene: createShadowsScene,
});

scene.ts

import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera";
import { Engine } from "@babylonjs/core/Engines/engine";
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
import { Color3 } from "@babylonjs/core/Maths/math.color";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { CubeTexture } from "@babylonjs/core/Materials/Textures/cubeTexture";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder";
import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder";
import { CreateTorus } from "@babylonjs/core/Meshes/Builders/torusBuilder";
import { Scene } from "@babylonjs/core/scene";
import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent";

export function createShadowsScene(engine: Engine, canvas: HTMLCanvasElement): Scene {
    const scene = new Scene(engine);
    const camera = new ArcRotateCamera("Camera", 0, 0, 10, Vector3.Zero(), scene);
    const light = new DirectionalLight("dir01", new Vector3(0, -1, -0.2), scene);
    const light2 = new DirectionalLight("dir02", new Vector3(-1, -2, -1), scene);

    light.position = new Vector3(0, 30, 0);
    light2.position = new Vector3(10, 20, 10);
    light.intensity = 0.6;
    light2.intensity = 0.6;

    camera.setPosition(new Vector3(-20, 20, 0));
    camera.attachControl(canvas, true);

    const skybox = CreateBox("skyBox", { size: 1000 }, scene);
    const skyboxMaterial = new StandardMaterial("skyBox", scene);
    const skyboxTexture = new CubeTexture("/Scenes/Customs/skybox/night", scene);
    skyboxTexture.coordinatesMode = Texture.SKYBOX_MODE;
    skyboxMaterial.backFaceCulling = false;
    skyboxMaterial.reflectionTexture = skyboxTexture;
    skyboxMaterial.diffuseColor = Color3.Black();
    skyboxMaterial.specularColor = Color3.Black();
    skyboxMaterial.disableLighting = true;
    skybox.material = skyboxMaterial;

    const ground = CreateGround("ground", { width: 1000, height: 1000, subdivisions: 1 }, scene);
    const groundMaterial = new StandardMaterial("ground", scene);
    const grassTexture = new Texture("./grass.jpg", scene);
    grassTexture.uScale = 60;
    grassTexture.vScale = 60;
    groundMaterial.diffuseTexture = grassTexture;
    groundMaterial.specularColor = Color3.Black();
    ground.position.y = -2.05;
    ground.material = groundMaterial;

    const torus = CreateTorus("torus", { diameter: 8, thickness: 2, tessellation: 32 }, scene);
    torus.position.y = 6;
    const torus2 = CreateTorus("torus2", { diameter: 4, thickness: 1, tessellation: 32 }, scene);
    torus2.position.y = 6;

    const torusMaterial = new StandardMaterial("torus", scene);
    torusMaterial.diffuseColor = new Color3(0.5, 0.5, 0.5);
    torusMaterial.specularColor = new Color3(0.5, 0.5, 0.5);
    torus.material = torusMaterial;
    torus2.material = torusMaterial;

    const shadowGenerator = new ShadowGenerator(512, light);
    shadowGenerator.getShadowMap()?.renderList?.push(torus, torus2);
    shadowGenerator.useExponentialShadowMap = true;

    const shadowGenerator2 = new ShadowGenerator(512, light2);
    shadowGenerator2.getShadowMap()?.renderList?.push(torus, torus2);
    shadowGenerator2.useExponentialShadowMap = true;

    ground.receiveShadows = true;

    scene.registerBeforeRender(() => {
        camera.beta = Math.min(Math.max(camera.beta, 0.1), (Math.PI / 2) * 0.99);
        camera.radius = Math.min(Math.max(camera.radius, 5), 150);
        torus.rotation.x += 0.01;
        torus.rotation.z += 0.02;
        torus2.rotation.x += 0.02;
        torus2.rotation.y += 0.01;
    });

    return scene;
}