Meshes and Geometry

Meshes are the 3D objects that populate your scene. Babylon.js provides comprehensive tools for creating, manipulating, and optimizing meshes, from built-in primitive shapes to complex imported models.

Babylon.js includes a variety of parametric shapes through the MeshBuilder class:

// Create a sphere
const sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {
    diameter: 2,
    segments: 32,
    updatable: true  // Allow geometry to be modified later
}, scene);

// Create a box/cube
const box = BABYLON.MeshBuilder.CreateBox("box", {
    size: 2,         // Size in all dimensions
    width: 3,        // Override specific dimensions
    height: 1,
    depth: 2,
    faceColors: [    // Color each face differently
        new BABYLON.Color4(1,0,0,1),  // red front
        new BABYLON.Color4(0,1,0,1),  // green back
        BABYLON.Color4.Blue(),        // blue top
        BABYLON.Color4.White(),       // white bottom
        BABYLON.Color4.Yellow(),      // yellow right
        BABYLON.Color4.Cyan()         // cyan left
    ]
}, scene);

// Create a plane
const plane = BABYLON.MeshBuilder.CreatePlane("plane", {
    width: 10,
    height: 5,
    sideOrientation: BABYLON.Mesh.DOUBLESIDE  // Visible from both sides
}, scene);

// Create a cylinder
const cylinder = BABYLON.MeshBuilder.CreateCylinder("cylinder", {
    height: 3,
    diameterTop: 1,
    diameterBottom: 2,
    tessellation: 24,     // Number of segments around circumference
    subdivisions: 1       // Number of height segments
}, scene);

// Create a torus (donut)
const torus = BABYLON.MeshBuilder.CreateTorus("torus", {
    diameter: 5,
    thickness: 1,
    tessellation: 32
}, scene);

// Create a ground mesh
const ground = BABYLON.MeshBuilder.CreateGround("ground", {
    width: 100,
    height: 100,
    subdivisions: 20,  // Increases detail for height maps
    updatable: false
}, scene);

Position, rotate, and scale meshes to arrange your scene:

// Position (translation)
box.position = new BABYLON.Vector3(0, 2, 0);  // Set absolute position
box.position.y += 1;                          // Relative position change

// Rotation (in radians)
cylinder.rotation = new BABYLON.Vector3(
    0,                // X-axis rotation (pitch)
    Math.PI / 4,      // Y-axis rotation (yaw)
    0                 // Z-axis rotation (roll)
);

// Alternative rotation with Quaternions (better for complex rotations)
const quaternion = BABYLON.Quaternion.RotationAxis(
    new BABYLON.Vector3(1, 1, 0).normalize(), // Axis to rotate around
    Math.PI / 3                              // Angle in radians
);
sphere.rotationQuaternion = quaternion;

// Scaling
torus.scaling = new BABYLON.Vector3(1.5, 1.5, 1.5);  // Uniform scaling
plane.scaling = new BABYLON.Vector3(2, 1, 1);       // Non-uniform scaling

// Apply multiple transformations with a matrix
const matrix = BABYLON.Matrix.Compose(
    new BABYLON.Vector3(1.2, 0.8, 1.2),                 // Scaling
    BABYLON.Quaternion.RotationYawPitchRoll(0.3, 0, 0), // Rotation
    new BABYLON.Vector3(2, 0, -3)                       // Translation
);
ground.setPivotMatrix(matrix);

Create parent-child relationships between meshes:

// Create parent node
const parent = new BABYLON.TransformNode("parent", scene);
parent.position.y = 5;

// Make meshes children of the parent
sphere.parent = parent;
box.parent = parent;

// Position children relative to parent
sphere.position = new BABYLON.Vector3(2, 0, 0);  // 2 units right of parent
box.position = new BABYLON.Vector3(-2, 0, 0);    // 2 units left of parent

// Rotate the parent (affects all children)
parent.rotation.y = Math.PI / 4;

Load 3D models created in external applications:

// Load a single model (glTF or GLB format - recommended)
BABYLON.SceneLoader.ImportMesh(
    "",                           // Names of meshes to import (empty = all)
    "./models/",                  // Path to models
    "character.glb",              // Filename
    scene,                         // Scene to import into
    (meshes, particleSystems, skeletons, animationGroups) => {
        // Successfully imported
        const character = meshes[0];
        character.scaling = new BABYLON.Vector3(0.1, 0.1, 0.1);
        
        // Play animations if available
        if (animationGroups.length > 0) {
            animationGroups[0].start(true);  // true = loop
        }
    }
);

// Asynchronous loading with await
async function loadModel() {
    const result = await BABYLON.SceneLoader.ImportMeshAsync(
        "", "./models/", "scene.gltf", scene
    );
    
    // Process imported meshes
    for (const mesh of result.meshes) {
        mesh.checkCollisions = true;
    }
    
    // Handle animations
    if (result.animationGroups.length > 0) {
        const idleAnim = result.animationGroups.find(g => g.name === "Idle");
        if (idleAnim) idleAnim.start(true);
    }
}

// Load a complete scene (replaces current scene)
BABYLON.SceneLoader.Load("./models/", "environment.glb", engine, (newScene) => {
    // newScene is now the active scene
    newScene.createDefaultCameraOrLight(true, true, true);
});

Combine and modify meshes:

// Merge multiple meshes into one for better performance
const merged = BABYLON.Mesh.MergeMeshes(
    [box, sphere, cylinder],  // Meshes to merge
    true,                     // Dispose original meshes
    true,                     // Allow different materials
    undefined,                // Use default world matrix
    false,                    // Don't clone meshes
    true                      // Allow different vertex colors
);

// Create instances for repeated objects with shared geometry
const boxInstance = box.createInstance("boxInstance");
boxInstance.position.x = 5;

// Create many instances efficiently
for (let i = 0; i < 100; i++) {
    const instance = box.createInstance("box" + i);
    instance.position = new BABYLON.Vector3(
        Math.random() * 20 - 10,
        Math.random() * 5,
        Math.random() * 20 - 10
    );
    instance.rotation.y = Math.random() * Math.PI * 2;
}

Create custom meshes with vertex data:

// Create a custom mesh (triangle)
const customMesh = new BABYLON.Mesh("custom", scene);

// Define vertex data
const vertexData = new BABYLON.VertexData();

// Positions (3 vertices, each with x,y,z coordinates)
vertexData.positions = [
    0, 1, 0,    // Top vertex
    -1, -1, 0,  // Bottom left vertex
    1, -1, 0    // Bottom right vertex
];

// Indices (defines triangles using position indices)
vertexData.indices = [0, 1, 2]; // Counter-clockwise winding

// Normals (perpendicular vectors for lighting calculations)
vertexData.normals = [
    0, 0, 1,
    0, 0, 1,
    0, 0, 1
];

// UV coordinates for texturing
vertexData.uvs = [
    0.5, 0,   // Top vertex UV
    0, 1,     // Bottom left UV
    1, 1      // Bottom right UV
];

// Apply the vertex data to the mesh
vertexData.applyToMesh(customMesh);

Optimize meshes for better performance:

// Freeze transformations (improves performance)
box.freezeWorldMatrix();

// Convert to a thin instance mesh (very efficient for many copies)
const matrix1 = BABYLON.Matrix.Translation(3, 0, 0);
const matrix2 = BABYLON.Matrix.Translation(-3, 0, 0);
const matrix3 = BABYLON.Matrix.Translation(0, 0, 3);

sphere.thinInstanceSetBuffer("matrix", [matrix1, matrix2, matrix3]);

// Level of Detail (LOD)
const highDetailSphere = BABYLON.MeshBuilder.CreateSphere("highDetail", {
    segments: 32,
    diameter: 2
}, scene);

const mediumDetailSphere = BABYLON.MeshBuilder.CreateSphere("mediumDetail", {
    segments: 16,
    diameter: 2
}, scene);

const lowDetailSphere = BABYLON.MeshBuilder.CreateSphere("lowDetail", {
    segments: 8,
    diameter: 2
}, scene);

// Add LOD levels
highDetailSphere.addLODLevel(30, mediumDetailSphere);  // Switch at 30 units distance
highDetailSphere.addLODLevel(60, lowDetailSphere);     // Switch at 60 units distance
highDetailSphere.addLODLevel(100, null);               // Hide beyond 100 units

// Only the highDetailSphere needs to be visible in the scene
mediumDetailSphere.isVisible = false;
lowDetailSphere.isVisible = false;

Babylon.js 7 introduces improved mesh features:

// Enable mesh tessellation (dynamic subdivision)
ground.enableTessellation = true;
ground.tessellationProperties = {
    maxSubdivisions: 8,   // Maximum subdivision level
    distanceFunction: (x, y, z, camera) => {
        // Custom function to determine subdivision based on distance
        const distanceToCamera = BABYLON.Vector3.Distance(
            new BABYLON.Vector3(x, y, z),
            camera.position
        );
        return Math.max(1, 8 - Math.floor(distanceToCamera / 10));
    }
};

// GPU instancing with custom attributes
const buffer = new Float32Array(4 * 100); // 100 instances, 4 values each
for (let i = 0; i < 100; i++) {
    // Custom color and scale for each instance
    buffer[i*4] = Math.random();   // R
    buffer[i*4+1] = Math.random(); // G
    buffer[i*4+2] = Math.random(); // B
    buffer[i*4+3] = 0.5 + Math.random() * 0.5; // Scale
}

sphere.thinInstanceSetBuffer("color", buffer, 4);

// Create vertex shader that uses the buffer
const shader = new BABYLON.ShaderMaterial(/* shader code that accesses custom attributes */);
sphere.material = shader;

These mesh capabilities in Babylon.js 7 provide powerful tools for creating and optimizing 3D objects, from simple primitives to complex imported models, with performance optimizations for both desktop and mobile platforms.