Script: BabylonJS 3D Logo

BabylonJS 3D Logo picture
Type
Typescript logo indicatortypescript
Author
matas
Date Created
Oct 25, 2023, 11:19:14 AM
Last Edit Date
Dec 5, 2023, 2:10:02 PM

Project Information

It is now possible to use complete BabylonJS Core on our Monaco editor and integrate it seamlessly with bitbybit algorithms.

View Full Project

Script Code

// We use bitbybit to get the default engine
const engine = bitbybit.babylon.engine.getEngine();

const scene = new BABYLON.Scene(engine);

// It is important to inform bitbybit that we use non-default scene
bitbybit.babylon.scene.setAndAttachScene({ scene });

var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(2, 2, -2), scene);
camera.setTarget(BABYLON.Vector3.Zero());

// We can only re-use the existing rendering canvas from default engine
const canvas = bitbybit.babylon.engine.getRenderingCanvas();

camera.attachControl(canvas, true);
camera.speed = 0.05;
camera.minZ = 0;

scene.clearColor = new BABYLON.Color4(26 / 255, 28 / 255, 31 / 255, 1);

// BabylonJS way of creating lights
const light = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(0, 1, 0), scene);
light.intensityMode = BABYLON.Light.INTENSITYMODE_ILLUMINANCE;
light.intensity = 1;

const createPointLightThroughBitByBit = async () => {
    // Bitbybit way of creating a point light, which also will create shadow generator and do some magic
    const ptLightDto = new Bit.Inputs.BabylonScene.PointLightDto();
    ptLightDto.position = [0.7, 2, -1.5];
    ptLightDto.intensity = 400;
    ptLightDto.radius = 0.1;
    bitbybit.babylon.scene.drawPointLight(ptLightDto);
}

const createBabylonJSLogo = async () => {

    const baseCube = await bitbybit.occt.shapes.solid.createBox({
        width: 1, height: 1, length: 1, center: [0, 0, 0]
    });

    const thirdSize = 0.33333334;
    const twoThirdsSize = 0.666666667;
    const halfThird = 0.1666666;

    const baseCutout = await bitbybit.occt.shapes.solid.createBox({
        width: thirdSize, height: thirdSize, length: thirdSize, center: [thirdSize, thirdSize, -thirdSize]
    });

    const diffedCube = await bitbybit.occt.booleans.difference({
        shape: baseCube,
        shapes: [baseCutout],
        keepEdges: false,
    });

    const whiteBox1 = await bitbybit.occt.shapes.solid.createBox({
        width: twoThirdsSize, height: twoThirdsSize, length: twoThirdsSize, center: [halfThird, halfThird, -halfThird]
    });

    const whiteBox2 = await bitbybit.occt.shapes.solid.createBox({
        width: thirdSize, height: twoThirdsSize, length: thirdSize, center: [0, halfThird, thirdSize]
    });

    const whiteUnion = await bitbybit.occt.booleans.union({
        shapes: [whiteBox1, whiteBox2],
        keepEdges: false,
    });

    const whiteCubeCutout = await bitbybit.occt.shapes.solid.createBox({
        width: 0.95, height: 0.95, length: 0.95, center: [0, 0, 0]
    });

    const diffedWhite = await bitbybit.occt.booleans.difference({
        shape: whiteUnion,
        shapes: [whiteCubeCutout, baseCutout],
        keepEdges: false,
    });

    const diffedRed = await bitbybit.occt.booleans.difference({
        shape: diffedCube,
        shapes: [diffedWhite],
        keepEdges: false,
    });

    const drawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
    drawOptions.drawEdges = false;

    const redPartMesh = await bitbybit.draw.drawAnyAsync({
        entity: diffedRed,
        options: drawOptions
    });

    const whitePartMesh = await bitbybit.draw.drawAnyAsync({
        entity: diffedWhite,
        options: drawOptions
    });

    // this is how you can access results of the drawing operation
    const surfaceMesh = whitePartMesh.getChildMeshes()[0];
    const mat = new BABYLON.PBRMetallicRoughnessMaterial("surface-material");
    mat.baseColor = new BABYLON.Color3(1, 1, 1);
    mat.metallic = 0.4;
    mat.roughness = 0.7;
    surfaceMesh.material = mat;

    // this will just group red and white meshes under one parent mesh
    const meshParent = new BABYLON.Mesh("parent-for-logo", scene);
    whitePartMesh.parent = meshParent;
    redPartMesh.parent = meshParent;

    return meshParent;
}

const createText = async () => {
    const textOptions = new Bit.Advanced.Text3D.Text3DDto();
    textOptions.text = "BabylonJS";
    textOptions.fontSize = 0.3;
    textOptions.height = 0.04;
    textOptions.origin = [1, 0, 0];
    textOptions.direction = [1, 0, 0];
    textOptions.rotation = 90;
    const text = await bitbybit.advanced.text3d.create(textOptions);
    // we center the text
    const textMoved = await bitbybit.occt.transforms.translate({ shape: text.compound, translation: [0, 0, -text.advanceWidth / 2] });

    const textDrawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
    textDrawOptions.edgeWidth = 0.3;
    textDrawOptions.edgeColour = "#ffffff";
    textDrawOptions.faceColour = "#ff0000";
    const drawnText = await bitbybit.draw.drawAnyAsync({
        entity: textMoved,
        options: textDrawOptions,
    });
    return drawnText;
}

const start = async () => {

    createPointLightThroughBitByBit();
    const logoMesh = await createBabylonJSLogo();
    const textMesh = await createText();

    const ground = await bitbybit.occt.shapes.face.createRectangleFace({
        width: 22,
        length: 22,
        center: [0, -0.5, 0],
        direction: [0, -1, 0],
    });

    const groundDrawOptions = new Bit.Inputs.Draw.DrawOcctShapeOptions();
    groundDrawOptions.faceOpacity = 0.4;
    bitbybit.draw.drawAnyAsync({
        entity: ground,
        options: groundDrawOptions
    });

    // this is one way to animate resulting mesh
    scene.onBeforeRenderObservable.add(s => {
        textMesh.rotate(new BABYLON.Vector3(0, 1, 0), -0.005);
    });

    // lets create a grid of instanced meshes
    const size = 10;
    const step = 2.5;
    for (let i = -size; i <= size; i += step) {
        for (let j = -size; j <= size; j += step) {
            // we need children because logo mesh consists of two childs - red and white mesh
            const children = logoMesh.getChildMeshes();
            children.forEach((c: BABYLON.Mesh) => {
                const verticeData = c.getVerticesData(BABYLON.VertexBuffer.PositionKind);
                if (verticeData && verticeData.length > 0) {
                    const inst = c.createInstance(`${i}-${j}-mesh-${c.name}`);
                    inst.position = new BABYLON.Vector3(i, -2, j);
                    scene.metadata.shadowGenerators.forEach(sh => {
                        sh.addShadowCaster(inst, true);
                    });
                }
            });
        }
    }

}
start();