BabylonJS - Animations
Babylon.js - Animations, Sprites, and Particles
Section titled “Babylon.js - Animations, Sprites, and Particles”Animation brings your 3D scenes to life. Babylon.js provides a powerful and flexible animation system capable of animating almost any property of an object over time, including position, rotation, scaling, material colors, light intensity, and more. This section also covers Sprites (2D images in 3D space) and Particle Systems (for effects like fire, smoke, etc.), which often involve animation principles.
Core Animation Concepts
Section titled “Core Animation Concepts”The core of the Babylon.js animation system involves:
BABYLON.AnimationObject: Defines what property to animate (e.g.,position.x), the type of data (e.g., float, vector, color), the animation speed (framePerSecond), and looping behavior.- Keyframes: An array defining the value of the animated property at specific frames (points in time).
- Target: The object whose property is being animated (e.g., a mesh, light, camera).
scene.beginAnimation: Starts the animation on a target object.
Creating an Animation
Section titled “Creating an Animation”import * as BABYLON from '@babylonjs/core';
// Assuming 'scene' and 'targetMesh' are defined
// 1. Create Animation objectconst frameRate = 30;const propertyToAnimate = "position.y"; // Animate vertical position
const yAnimation = new BABYLON.Animation( "yAnim", // Animation name propertyToAnimate, // Property to animate (can be nested, e.g., 'material.alpha') frameRate, // Frames per second BABYLON.Animation.ANIMATIONTYPE_FLOAT, // Data type (FLOAT, VECTOR3, COLOR3, QUATERNION, etc.) BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE // Loop behavior (CYCLE, RELATIVE, CONSTANT));
// 2. Create Keyframesconst keys = [];// At frame 0, position.y = 0keys.push({ frame: 0, value: 0 });// At frame 30 (1 second), position.y = 5keys.push({ frame: 30, value: 5 });// At frame 60 (2 seconds), position.y = 0keys.push({ frame: 60, value: 0 });
// 3. Assign Keys to AnimationyAnimation.setKeys(keys);
// 4. Link Animation to Target Mesh// Ensure the mesh has an 'animations' array initializedif (!targetMesh.animations) { targetMesh.animations = [];}targetMesh.animations.push(yAnimation);
// 5. Start the Animation// Parameters: target, start frame, end frame, loop (boolean), speed ratio, onAnimationEnd callbackconst animatable = scene.beginAnimation(targetMesh, 0, 60, true, 1.0);
// animatable allows controlling the running animation (pause, stop, etc.)// animatable.pause();Animation Loop Modes
Section titled “Animation Loop Modes”ANIMATIONLOOPMODE_CYCLE: Restarts the animation from the beginning value.ANIMATIONLOOPMODE_RELATIVE: Uses the end value as the starting point for the next loop iteration (good for continuous rotation or movement).ANIMATIONLOOPMODE_CONSTANT: Stops at the end value and holds it.
Demo: Animating Box Scaling
Section titled “Demo: Animating Box Scaling”<!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>Babylon.js - Basic Animation</title> <script src="https://cdn.babylonjs.com/babylon.js"></script> <style> html, body { overflow: hidden; width: 100%; height: 100%; margin: 0; padding: 0; } #renderCanvas { width: 100%; height: 100%; touch-action: none; } </style></head><body> <canvas id="renderCanvas"></canvas> <script type="text/javascript"> const canvas = document.getElementById("renderCanvas"); const engine = new BABYLON.Engine(canvas, true);
const createScene = function () { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0.1, 0.2, 0.1, 1.0);
const camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2.5, 15, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true);
const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.intensity = 0.8;
const box = BABYLON.MeshBuilder.CreateBox("box", { size: 2 }, scene); box.position.x = -3; const boxMat = new BABYLON.StandardMaterial("boxMat", scene); boxMat.diffuseColor = BABYLON.Color3.Red(); box.material = boxMat;
const box2 = BABYLON.MeshBuilder.CreateBox("box2", { size: 2 }, scene); box2.position.x = 3; const box2Mat = new BABYLON.StandardMaterial("box2Mat", scene); box2Mat.diffuseColor = BABYLON.Color3.Blue(); box2.material = box2Mat;
// --- Animation for Box 1 (Scaling X) --- const scaleXAnim = new BABYLON.Animation("scaleXAnim", "scaling.x", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE); const scaleKeys = []; scaleKeys.push({ frame: 0, value: 1 }); scaleKeys.push({ frame: 30, value: 0.2 }); scaleKeys.push({ frame: 60, value: 1.5 }); scaleKeys.push({ frame: 90, value: 1 }); scaleXAnim.setKeys(scaleKeys); box.animations.push(scaleXAnim); scene.beginAnimation(box, 0, 90, true); // ---------------------------------------
// --- Animation for Box 2 (Rotation Y - Relative) --- const rotateYAnim = new BABYLON.Animation("rotateYAnim", "rotation.y", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE); const rotateKeys = []; rotateKeys.push({ frame: 0, value: 0 }); rotateKeys.push({ frame: 60, value: Math.PI * 2 }); // One full rotation over 2 seconds rotateYAnim.setKeys(rotateKeys); box2.animations.push(rotateYAnim); scene.beginAnimation(box2, 0, 60, true); // ----------------------------------------
return scene; };
const scene = createScene(); engine.runRenderLoop(function () { scene.render(); }); window.addEventListener("resize", function () { engine.resize(); }); </script></body></html>Output Description (Animation Demo)
Section titled “Output Description (Animation Demo)”This demo shows two cubes. The red cube on the left continuously scales along its X-axis (width), shrinking, then growing larger, then returning to normal size, looping the cycle. The blue cube on the right rotates continuously around its Y-axis using relative looping, making it spin indefinitely.
Controlling Animations
Section titled “Controlling Animations”The Animatable object returned by scene.beginAnimation allows control:
animatable.pause(): Pauses the animation.animatable.restart(): Restarts the animation from the beginning.animatable.stop(): Stops the animation and removes it.animatable.goToFrame(frameNumber): Jumps to a specific frame.
Easier Animation with CreateAndStartAnimation
Section titled “Easier Animation with CreateAndStartAnimation”For simple animations between two values, use the static helper:
// Animate box position.x from current value to 5 over 120 frames (4 seconds at 30fps)BABYLON.Animation.CreateAndStartAnimation( 'boxSlide', // Animation name box, // Target mesh 'position.x',// Property to animate 30, // FPS 120, // Total frames box.position.x, // Starting value 5, // Ending value BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT // Loop mode (e.g., play once));Easing Functions
Section titled “Easing Functions”Easing functions control the rate of change in an animation, making movement appear more natural (e.g., starting slow, speeding up, then slowing down). You apply an easing function to an Animation object.
// Create an easing function (e.g., quadratic ease in/out)const easingFunc = new BABYLON.QuadraticEase();
// Set easing mode (EaseIn, EaseOut, EaseInOut)easingFunc.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
// Apply it to an animation object BEFORE setting keys or startingmyAnimation.setEasingFunction(easingFunc);Common easing functions include: LinearEase, CircleEase, BackEase, BounceEase, CubicEase, ElasticEase, ExponentialEase, PowerEase, QuadraticEase, QuarticEase, QuinticEase, SineEase.
Animation Events
Section titled “Animation Events”You can trigger code at specific frames within an animation.
// Create an event to trigger at frame 50const animEvent = new BABYLON.AnimationEvent( 50, // Frame number () => { console.log("Reached frame 50!"); }, // Action callback true // Only trigger once?);
// Add the event to the animation objectmyAnimation.addEvent(animEvent);Sprites
Section titled “Sprites”Sprites are 2D images used within a 3D scene. They are efficient for rendering large numbers of simple objects like trees, grass, particles, or billboarded characters. Sprites always face the camera (billboarding) by default.
Sprites are managed by a SpriteManager, which optimizes rendering. You create a manager for each sprite sheet (texture) you want to use.
// 1. Create a Sprite Manager// Parameters: name, texture URL, capacity (max sprites), cell size (width/height), sceneconst spriteManager = new BABYLON.SpriteManager( "treeManager", "textures/tree.png", // Image containing the sprite(s) 2000, // Max number of trees this manager can handle { width: 64, height: 64 }, // Size of each sprite cell in the texture scene);
// 2. Create Sprite Instancesconst treeSprite = new BABYLON.Sprite("tree", spriteManager);
// 3. Position and configure the sprite instancetreeSprite.position = new BABYLON.Vector3(5, 0.5, 10);treeSprite.size = 2.0; // Adjust display size// treeSprite.angle = Math.PI / 4; // Rotate the sprite plane// treeSprite.cellIndex = 0; // If sprite sheet has multiple cells, select one
// You can create many sprites using the same managerfor (let i = 0; i < 100; i++) { const anotherTree = new BABYLON.Sprite("tree" + i, spriteManager); anotherTree.position = new BABYLON.Vector3(Math.random() * 50 - 25, 0.5, Math.random() * 50 - 25); anotherTree.size = 1.5 + Math.random(); // Random size}Sprite Animation
Section titled “Sprite Animation”If your sprite texture contains multiple frames of an animation (a sprite sheet), you can animate it using sprite.playAnimation().
// Assuming 'playerSpriteSheet.png' has animation frames in cells 0 to 7const playerManager = new BABYLON.SpriteManager("playerMgr", "textures/playerSpriteSheet.png", 1, {width: 64, height: 64}, scene);const player = new BABYLON.Sprite("player", playerManager);player.position.y = 0.5;
// Play animation from cell 0 to 7, loop, at 100ms delay per frameplayer.playAnimation(0, 7, true, 100);Particle Systems
Section titled “Particle Systems”Particle systems are used to simulate phenomena involving many small elements, such as fire, smoke, explosions, rain, sparks, or magic effects. Babylon.js has CPU-based (ParticleSystem) and high-performance GPU-based (GPUParticleSystem) particle systems.
You configure a particle system by defining properties like the emitter (where particles originate), textures, colors over lifetime, size over lifetime, emission rate, lifetime duration, speed, gravity, etc.
// 1. Create a Particle System (using GPU for better performance)const particleSystem = new BABYLON.GPUParticleSystem("particles", { capacity: 5000 }, scene);// For CPU: new BABYLON.ParticleSystem("particles", 5000, scene);
// 2. Set Particle TextureparticleSystem.particleTexture = new BABYLON.Texture("textures/flare.png", scene);
// 3. Set Emitter (where particles come from)// Can be a Vector3 point or a mesh// particleSystem.emitter = new BABYLON.Vector3(0, 1, 0); // Emit from a pointconst fountainMesh = BABYLON.MeshBuilder.CreateBox("fountainEmitter", {size: 0.1}, scene);fountainMesh.isVisible = false; // Hide the emitter mesh itselfparticleSystem.emitter = fountainMesh;
// Or emit from a volume (e.g., inside a box)particleSystem.minEmitBox = new BABYLON.Vector3(-0.5, 0, -0.5);particleSystem.maxEmitBox = new BABYLON.Vector3(0.5, 0, 0.5);
// 4. Configure Particle Appearance & Behavior// ColorsparticleSystem.color1 = new BABYLON.Color4(1, 0.5, 0, 1.0); // Start color (e.g., orange)particleSystem.color2 = new BABYLON.Color4(1, 0, 0, 1.0); // Mid color (e.g., red)particleSystem.colorDead = new BABYLON.Color4(0.2, 0, 0, 0.0); // End color (e.g., dark red, transparent)
// SizeparticleSystem.minSize = 0.1;particleSystem.maxSize = 0.5;
// LifetimeparticleSystem.minLifeTime = 0.5; // secondsparticleSystem.maxLifeTime = 2.0; // seconds
// Emission RateparticleSystem.emitRate = 1000; // Particles per second
// Emission Direction (example: upward fountain)particleSystem.direction1 = new BABYLON.Vector3(-0.2, 0.8, -0.2);particleSystem.direction2 = new BABYLON.Vector3(0.2, 0.8, 0.2);
// SpeedparticleSystem.minEmitPower = 1;particleSystem.maxEmitPower = 3;particleSystem.updateSpeed = 0.01; // Simulation speed adjustment
// GravityparticleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);
// Blending Mode (for transparent textures)particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE; // Additive blending often looks good for fire/magic
// 5. Start the systemparticleSystem.start();
// To stop: particleSystem.stop();// To dispose: particleSystem.dispose();Demo Description (Particles & Sprites)
Section titled “Demo Description (Particles & Sprites)”Imagine combining these concepts. Create a ground plane. Use a SpriteManager to scatter hundreds of tree sprites across it randomly. Create a GPUParticleSystem with a flare.png texture, configure it to look like smoke (grayish colors, slow upward movement, low gravity, longer lifetime), set its emitter position, and start it. The result would be a landscape with many trees and a smoking effect rising from a specific point.