VectorPosition and Rotation
BabylonJS - Positioning and Rotating Meshes
Section titled “BabylonJS - Positioning and Rotating Meshes”Understanding how to position and orient objects in 3D space is fundamental. BabylonJS uses a right-handed coordinate system. By default:
- X-axis: Points to the right.
- Y-axis: Points upwards.
- Z-axis: Points out of the screen, towards you.
We’ll use BABYLON.Vector3 to represent positions and rotations (as Euler angles).
Visualizing Axes
Section titled “Visualizing Axes”The following code includes a helper function showAxis that draws lines and labels for the X, Y, and Z axes, making it easier to visualize the coordinate system and object placement.
Axis Visualization Example
Section titled “Axis Visualization Example”import * as BABYLON from '@babylonjs/core';import '@babylonjs/gui'; // Needed for DynamicTexture used in showAxis
const canvas = document.getElementById('renderCanvas');const engine = new BABYLON.Engine(canvas, true);
const createScene = async function() { const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0.2, 0.2, 0.2, 1.0);
// Camera: Positioned to view the origin const camera = new BABYLON.ArcRotateCamera("camera", -Math.PI / 2 + 0.5, Math.PI / 2.5, 20, BABYLON.Vector3.Zero(), scene); camera.attachControl(canvas, true); camera.wheelPrecision = 50; // Adjust zoom speed
// Light const light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene); light.intensity = 0.8;
// --- Axis Visualization Function --- const showAxis = function(size) { const makeTextPlane = function(text, color, textSize) { const dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", { width: text.length * 20 + 20, // Adjust width based on text length height: 70 }, scene, false); dynamicTexture.hasAlpha = true; dynamicTexture.drawText(text, null, null, "bold 36px Arial", color, "transparent", true);
const plane = BABYLON.MeshBuilder.CreatePlane("TextPlane", {size: textSize}, scene); plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", scene); // StandardMaterial works well for unlit text plane.material.backFaceCulling = false; plane.material.specularColor = new BABYLON.Color3(0, 0, 0); plane.material.diffuseTexture = dynamicTexture; plane.material.useAlphaFromDiffuseTexture = true; return plane; };
const axisX = BABYLON.MeshBuilder.CreateLines("axisX", { points: [ new BABYLON.Vector3(-size, 0, 0), new BABYLON.Vector3(size, 0, 0) ] }, scene); axisX.color = new BABYLON.Color3(1, 0, 0); const xChar = makeTextPlane("X", "red", size / 10); xChar.position = new BABYLON.Vector3(size * 0.9, 0.05 * size, 0); // Add numbers along X for (let i = -size; i <= size; i++) { if (i === 0) continue; const xNum = makeTextPlane(i.toString(), "red", size / 20); xNum.position = new BABYLON.Vector3(i, 0.05 * size, 0); }
const axisY = BABYLON.MeshBuilder.CreateLines("axisY", { points: [ new BABYLON.Vector3(0, -size, 0), new BABYLON.Vector3(0, size, 0) ] }, scene); axisY.color = new BABYLON.Color3(0, 1, 0); const yChar = makeTextPlane("Y", "green", size / 10); yChar.position = new BABYLON.Vector3(0, size * 0.9, 0.05 * size); // Add numbers along Y for (let i = -size; i <= size; i++) { if (i === 0) continue; const yNum = makeTextPlane(i.toString(), "green", size / 20); yNum.position = new BABYLON.Vector3(0, i, 0.05 * size); }
const axisZ = BABYLON.MeshBuilder.CreateLines("axisZ", { points: [ new BABYLON.Vector3(0, 0, -size), new BABYLON.Vector3(0, 0, size) ] }, scene); axisZ.color = new BABYLON.Color3(0, 0, 1); const zChar = makeTextPlane("Z", "blue", size / 10); zChar.position = new BABYLON.Vector3(0, 0.05 * size, size * 0.9); // Add numbers along Z for (let i = -size; i <= size; i++) { if (i === 0) continue; const zNum = makeTextPlane(i.toString(), "blue", size / 20); zNum.position = new BABYLON.Vector3(0, 0.05 * size, i); // Rotate Z labels to face camera better initially zNum.rotation.y = Math.PI / 2; } }; // --- End Axis Visualization Function ---
// Call the function to draw axes of size 10 showAxis(10);
return scene;};
createScene().then(scene => { engine.runRenderLoop(function() { if (scene) { scene.render(); } });});
window.addEventListener('resize', function() { engine.resize();});This example draws red (X), green (Y), and blue (Z) lines originating from (0,0,0) with labels and number markers. Run this code to get a clear visual reference for the coordinate system.
Note: The makeTextPlane function uses DynamicTexture to draw text onto a plane mesh. For more complex UI or text rendering, consider using the BabylonJS GUI extension (@babylonjs/gui).
Setting Mesh Position
Section titled “Setting Mesh Position”Every mesh has a position property, which is a BABYLON.Vector3. You can set its x, y, and z components directly or assign a new Vector3.
Positioning Examples
Section titled “Positioning Examples”// Inside createScene, after showAxis(10);
// --- Positioning Meshes ---
// Create a sphere materialconst sphereMat = new BABYLON.PBRMaterial("sphereMat", scene);sphereMat.albedoColor = new BABYLON.Color3(1, 1, 0); // YellowsphereMat.metallic = 0.2;sphereMat.roughness = 0.5;
// Sphere 1: Set components individuallyconst sphere1 = BABYLON.MeshBuilder.CreateSphere("sphere1", {diameter: 2}, scene);sphere1.material = sphereMat;sphere1.position.x = 5;sphere1.position.y = 2;sphere1.position.z = 3;// Final position: (5, 2, 3)
// Sphere 2: Assign a new Vector3const sphere2 = BABYLON.MeshBuilder.CreateSphere("sphere2", {diameter: 1.5}, scene);sphere2.material = sphereMat;sphere2.position = new BABYLON.Vector3(-4, 1, -2);// Final position: (-4, 1, -2)
// Sphere 3: Default position is (0, 0, 0)const sphere3 = BABYLON.MeshBuilder.CreateSphere("sphere3", {diameter: 1}, scene);sphere3.material = sphereMat;// Final position: (0, 0, 0)
// --- Moving Meshes (Relative Positioning) ---
// Move sphere1 2 units along the positive X-axis from its current positionsphere1.position.x += 2; // Now at (7, 2, 3)
// Move sphere2 using addInPlaceconst moveVector = new BABYLON.Vector3(1, 2, 0);sphere2.position.addInPlace(moveVector); // Now at (-3, 3, -2)
// Translate sphere3 along its local Z-axis (initially world Z)// Note: This requires considering rotation if the mesh is rotated.// For simple translation along world axes, addInPlace or direct modification is simpler.sphere3.translate(BABYLON.Axis.Z, 5, BABYLON.Space.WORLD); // Now at (0, 0, 5)Key methods for positioning:
mesh.position: Get or set the mesh’s positionVector3in world space.mesh.position.x / .y / .z: Access individual components.mesh.position.addInPlace(vector): Adds thevectorcomponents to the mesh’s current position (modifiesmesh.position). Efficient for frequent updates.mesh.translate(axis, distance, space): Moves the mesh along a specifiedaxis(BABYLON.Axis.X/Y/Z) by adistance.spacecan beBABYLON.Space.LOCAL(relative to mesh’s rotation) orBABYLON.Space.WORLD.
Setting Mesh Rotation
Section titled “Setting Mesh Rotation”Rotation is often represented using Euler angles (rotations around the X, Y, and Z axes). BabylonJS stores this in the mesh.rotation property (a Vector3) where components represent angles in radians.
Alternatively, quaternions (mesh.rotationQuaternion) are used for more complex or numerically stable rotations, especially when interpolating or avoiding gimbal lock. For basic rotations, Euler angles are often simpler.
Remember: Angles are in Radians! To convert degrees to radians, use the formula: radians = degrees * (Math.PI / 180).
Rotation Examples
Section titled “Rotation Examples”// Inside createScene...
// --- Rotating Meshes ---
// Create a box materialconst boxMat = new BABYLON.PBRMaterial("boxMat", scene);boxMat.albedoColor = new BABYLON.Color3(0.6, 0.6, 1.0); // Light BlueboxMat.metallic = 0.1;boxMat.roughness = 0.7;
// Box 1: Rotate 45 degrees around the Y-axisconst box1 = BABYLON.MeshBuilder.CreateBox("box1", {width: 4, height: 1, depth: 2}, scene);box1.material = boxMat;box1.position = new BABYLON.Vector3(-5, 0.5, 5);box1.rotation.y = Math.PI / 4; // 45 degrees in radians
// Box 2: Set multiple rotationsconst box2 = BABYLON.MeshBuilder.CreateBox("box2", {size: 2}, scene);box2.material = boxMat;box2.position = new BABYLON.Vector3(5, 1, -5);box2.rotation = new BABYLON.Vector3( BABYLON.Tools.ToRadians(30), // 30 degrees around X BABYLON.Tools.ToRadians(0), // 0 degrees around Y BABYLON.Tools.ToRadians(-45) // -45 degrees around Z);
// Box 3: Add rotation incrementally (e.g., in render loop)const box3 = BABYLON.MeshBuilder.CreateBox("box3", {size: 1.5}, scene);box3.material = boxMat;box3.position = new BABYLON.Vector3(0, 0.75, 0);
scene.onBeforeRenderObservable.add(() => { // Rotate box3 around its local Y-axis each frame box3.rotation.y += 0.01; // Rotate box1 around world X-axis slowly box1.rotate(BABYLON.Axis.X, 0.005, BABYLON.Space.WORLD);});
// Using Quaternions (Alternative)const box4 = BABYLON.MeshBuilder.CreateBox("box4", {size: 1}, scene);box4.material = boxMat;box4.position = new BABYLON.Vector3(3, 0.5, 3);
// Rotate 90 degrees around an arbitrary axis (e.g., normalized vector (1, 1, 0))const rotationAxis = new BABYLON.Vector3(1, 1, 0).normalize();const angle = Math.PI / 2; // 90 degreesbox4.rotationQuaternion = BABYLON.Quaternion.RotationAxis(rotationAxis, angle);Key methods for rotation:
mesh.rotation: Get or set the mesh’s Euler rotationVector3(in radians).mesh.rotation.x / .y / .z: Access individual rotation components (radians).BABYLON.Tools.ToRadians(degrees): Helper function to convert degrees to radians.mesh.addRotation(x, y, z): Adds the given radian values to the currentmesh.rotationcomponents.mesh.rotate(axis, angle, space): Rotates the mesh around a specifiedaxis(BABYLON.Axis.X/Y/Zor a customVector3) by anangle(radians).spacecan beBABYLON.Space.LOCALorBABYLON.Space.WORLD.mesh.rotationQuaternion: Get or set the mesh’s rotation using aBABYLON.Quaternion. Useful for avoiding gimbal lock and for smooth interpolations. Various static methods onBABYLON.Quaternionhelp create them (e.g.,RotationAxis,RotationYawPitchRoll).
Experiment by changing the position and rotation values in the examples while using the axis visualization to see how the objects are placed and oriented in the 3D scene.