Babylon.js - Procedural Textures demo source

Back to demo

main.ts

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

runDemo({ createScene: createProceduralScene });

scene.ts

import type { Engine } from "@babylonjs/core/Engines/engine";
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera";
import { DirectionalLight } from "@babylonjs/core/Lights/directionalLight";
import { ShadowGenerator } from "@babylonjs/core/Lights/Shadows/shadowGenerator";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
import { CustomProceduralTexture } from "@babylonjs/core/Materials/Textures/Procedurals/customProceduralTexture";
import { Color3 } from "@babylonjs/core/Maths/math.color";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";
import { Space } from "@babylonjs/core/Maths/math.axis";
import { CreateBox } from "@babylonjs/core/Meshes/Builders/boxBuilder";
import { CreateCylinder } from "@babylonjs/core/Meshes/Builders/cylinderBuilder";
import { CreateSphere } from "@babylonjs/core/Meshes/Builders/sphereBuilder";
import { CreateTorus } from "@babylonjs/core/Meshes/Builders/torusBuilder";
import { CreateGround } from "@babylonjs/core/Meshes/Builders/groundBuilder";
import type { Mesh } from "@babylonjs/core/Meshes/mesh";
import { Scene } from "@babylonjs/core/scene";
import "@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent";
import { WoodProceduralTexture } from "@babylonjs/procedural-textures/wood/woodProceduralTexture";
import { GrassProceduralTexture } from "@babylonjs/procedural-textures/grass/grassProceduralTexture";
import { MarbleProceduralTexture } from "@babylonjs/procedural-textures/marble/marbleProceduralTexture";
import { FireProceduralTexture } from "@babylonjs/procedural-textures/fire/fireProceduralTexture";
import { BrickProceduralTexture } from "@babylonjs/procedural-textures/brick/brickProceduralTexture";
import { RoadProceduralTexture } from "@babylonjs/procedural-textures/road/roadProceduralTexture";
import { CloudProceduralTexture } from "@babylonjs/procedural-textures/cloud/cloudProceduralTexture";

export function createProceduralScene(engine: Engine, canvas: HTMLCanvasElement): Scene {
    const scene = new Scene(engine);
    const camera = new ArcRotateCamera("Camera", 1, 1.2, 25, new Vector3(10, 0, 0), scene);
    camera.upperBetaLimit = 1.2;
    camera.attachControl(canvas, true);

    const name = "town";

    const woodMaterial = new StandardMaterial(name, scene);
    const woodTexture = new WoodProceduralTexture(name + "text", 1024, scene);
    woodTexture.ampScale = 50.0;
    woodMaterial.diffuseTexture = woodTexture;

    const grassMaterial = new StandardMaterial(name + "bawl", scene);
    const grassTexture = new GrassProceduralTexture(name + "textbawl", 256, scene);
    grassMaterial.ambientTexture = grassTexture;

    const marbleMaterial = new StandardMaterial("torus", scene);
    const marbleTexture = new MarbleProceduralTexture("marble", 512, scene);
    marbleTexture.numberOfTilesHeight = 5;
    marbleTexture.numberOfTilesWidth = 5;
    marbleMaterial.ambientTexture = marbleTexture;

    const fireMaterial = new StandardMaterial("fontainSculptur2", scene);
    const fireTexture = new FireProceduralTexture("fire", 256, scene);
    fireMaterial.diffuseTexture = fireTexture;
    fireMaterial.opacityTexture = fireTexture;

    const brickMaterial = new StandardMaterial(name, scene);
    const brickTexture = new BrickProceduralTexture(name + "text", 512, scene);
    brickTexture.numberOfBricksHeight = 2;
    brickTexture.numberOfBricksWidth = 3;
    brickMaterial.diffuseTexture = brickTexture;

    const light = new DirectionalLight("dir01", new Vector3(-0.5, -1, -0.5), scene);
    light.diffuse = new Color3(1, 1, 1);
    light.specular = new Color3(1, 1, 1);
    light.position = new Vector3(20, 40, 20);

    const square = CreateGround("square", { width: 20, height: 20, subdivisions: 2 }, scene);
    square.position = new Vector3(0, 0, 0);
    const customMaterial = new StandardMaterial("custommat", scene);
    const customProcText = new CustomProceduralTexture("customtext", "/Demos/Procedural/land", 1024, scene);
    customMaterial.ambientTexture = customProcText;
    square.material = customMaterial;

    const shadowGenerator = new ShadowGenerator(1024, light);
    shadowGenerator.usePoissonSampling = true;
    shadowGenerator.bias = 0;
    square.receiveShadows = true;

    const pushShadow = (mesh: Mesh) => {
        shadowGenerator.getShadowMap()!.renderList!.push(mesh);
    };

    const createBosquet = (bname: string, x: number, y: number, z: number) => {
        const bosquet = CreateBox(bname, { size: 2 }, scene);
        bosquet.position = new Vector3(x, y, z);
        bosquet.material = grassMaterial;

        const bosquetbawl = CreateBox(bname + "bawl", { size: 1 }, scene);
        bosquetbawl.position = new Vector3(x, y + 1, z);
        bosquetbawl.material = grassMaterial;

        pushShadow(bosquet);
        pushShadow(bosquetbawl);
    };

    const createTree = (tname: string, x: number, y: number, z: number) => {
        const trunk = CreateCylinder(
            tname + "trunk",
            { height: 7, diameterTop: 2, diameterBottom: 2, tessellation: 12, subdivisions: 1 },
            scene
        );
        trunk.position = new Vector3(x, y, z);
        trunk.material = woodMaterial;

        const leafs = CreateSphere(tname + "leafs", { segments: 20, diameter: 7 }, scene);
        leafs.position = new Vector3(x, y + 5.0, z);
        leafs.material = grassMaterial;

        pushShadow(trunk);
        pushShadow(leafs);
    };

    const createFontain = (x: number, y: number, z: number) => {
        const torus = CreateTorus("torus", { diameter: 5, thickness: 1, tessellation: 20 }, scene);
        torus.position = new Vector3(x, y, z);
        torus.material = marbleMaterial;

        const fontainGround = CreateBox("fontainGround", { size: 4 }, scene);
        fontainGround.position = new Vector3(x, y - 2, z);
        fontainGround.material = marbleMaterial;

        const fontainSculptur1 = CreateCylinder(
            "fontainSculptur1",
            { height: 2, diameterTop: 2, diameterBottom: 1, tessellation: 10, subdivisions: 1 },
            scene
        );
        fontainSculptur1.position = new Vector3(x, y, z);
        fontainSculptur1.material = marbleMaterial;

        const fontainSculptur2 = CreateSphere("fontainSculptur2", { segments: 7, diameter: 1.7 }, scene);
        fontainSculptur2.position = new Vector3(x, y + 0.9, z);
        fontainSculptur2.material = fireMaterial;
        fontainSculptur2.rotate(new Vector3(1.0, 0.0, 0.0), Math.PI / 2.0, Space.LOCAL);

        pushShadow(torus);
        pushShadow(fontainSculptur1);
        pushShadow(fontainSculptur2);
    };

    const createTorch = (cname: string, x: number, y: number, z: number) => {
        const brickblock = CreateBox(cname + "brickblock", { size: 1 }, scene);
        brickblock.position = new Vector3(x, y, z);
        brickblock.material = brickMaterial;

        const torchwood = CreateCylinder(
            cname + "torchwood",
            { height: 2, diameterTop: 0.25, diameterBottom: 0.1, tessellation: 12, subdivisions: 1 },
            scene
        );
        torchwood.position = new Vector3(x, y + 1, z);
        torchwood.material = woodMaterial;

        const leafs2 = CreateSphere(cname + "leafs2", { segments: 10, diameter: 1.2 }, scene);
        leafs2.position = new Vector3(x, y + 2, z);
        leafs2.material = grassMaterial;

        pushShadow(torchwood);
        pushShadow(leafs2);
        pushShadow(brickblock);
    };

    createBosquet("b1", -9, 1, 9);
    createBosquet("b2", -9, 1, -9);
    createBosquet("b3", 9, 1, 9);
    createBosquet("b4", 9, 1, -9);

    createTree("a1", 0, 3.5, 0);

    const macadam = CreateGround("macadam", { width: 20, height: 20, subdivisions: 2 }, scene);
    macadam.position = new Vector3(20, 0, 0);
    const customMaterialmacadam = new StandardMaterial("macadam", scene);
    const customProcTextmacadam = new RoadProceduralTexture("customtextroad", 512, scene);
    customMaterialmacadam.diffuseTexture = customProcTextmacadam;
    macadam.material = customMaterialmacadam;
    macadam.receiveShadows = true;

    createFontain(20, 0.25, 0);
    createTorch("torch1", 15, 0.5, 5);
    createTorch("torch2", 15, 0.5, -5);
    createTorch("torch3", 25, 0.5, 5);
    createTorch("torch4", 25, 0.5, -5);

    const boxCloud = CreateSphere("boxCloud", { segments: 100, diameter: 1000 }, scene);
    boxCloud.position = new Vector3(0, 0, 12);
    const cloudMaterial = new StandardMaterial("cloudMat", scene);
    const cloudProcText = new CloudProceduralTexture("cloud", 1024, scene);
    cloudMaterial.emissiveTexture = cloudProcText;
    cloudMaterial.backFaceCulling = false;
    cloudMaterial.emissiveTexture.coordinatesMode = Texture.FIXED_EQUIRECTANGULAR_MODE;
    boxCloud.material = cloudMaterial;

    scene.registerBeforeRender(() => {
        camera.alpha += 0.001 * scene.getAnimationRatio();
    });

    return scene;
}