Chapter 02Capsules

Using the CreateCapsule() method of the MeshBuilder class, we can make capsules.

let capsule = BABYLON.MeshBuilder.CreateCapsule("name", {options}, scene);

The first argument of the CreateCapsule() method is a String that we can use to retrieve the entire capsule mesh and data about the capsule later. The second argument is an object that specifies various properties of the capsule. The last argument is a reference to the scene in which the capsule will be inserted into.

<script>
var canvas = document.getElementById("renderCanvas");
var engine = new BABYLON.Engine(canvas, true);

function createScene(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 4, Math.PI / 2, 2, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule = BABYLON.MeshBuilder.CreateCapsule("capsule", {}, scene);
    capsule.material = mat;
    
    return scene;
};

var scene = createScene(canvas, engine);

engine.runRenderLoop(function(){
    scene.render();
});

window.addEventListener("resize", function(){
    engine.resize();
});
</script>

<canvas id="renderCanvas"></canvas>
Figure 1. Default Babylon.js Capsule.

Properties

Orientation

The orientation property specifies the axis which runs through the center of the capsule. The default value is Vector3.Up, which is straight up and down. We cannot put the capsule on an angle, and can only be on an axis.

<script>
var canvas1 = document.getElementById("renderCanvas1");
var engine1 = new BABYLON.Engine(canvas1, true);

function createLocalAxes(size, scene) {
    let [local_axisX, local_axisY, local_axisZ] = createAxis(size, scene);

    let origin = new BABYLON.TransformNode("origin");

    local_axisX.parent = origin;
    local_axisY.parent = origin;
    local_axisZ.parent = origin;

    return origin;
}

function createAxis(size, scene) {
    let makeTextPlane = function(text, color, size, camera, billboardMode) {
        let dynamicTexture = new BABYLON.DynamicTexture("DynamicTexture", 50, scene, true);
        dynamicTexture.hasAlpha = true;
        dynamicTexture.drawText(text, 5, 40, "bold 36px Arial", color , "transparent", true);

        let plane = new BABYLON.MeshBuilder.CreatePlane("TextPlane", {size: size, updatable: true}, scene);
        plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", scene);
        plane.material.specularColor = new BABYLON.Color3(0, 0, 0);
        plane.material.diffuseTexture = dynamicTexture;
        plane.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL;

        return plane;
    };

    let axisX = BABYLON.Mesh.CreateLines("axisX", [
        new BABYLON.Vector3.Zero(),
        new BABYLON.Vector3(size, 0, 0),
        new BABYLON.Vector3(size * 0.95, 0.05 * size, 0),
        new BABYLON.Vector3(size, 0, 0),
        new BABYLON.Vector3(size * 0.95, -0.05 * size, 0)
    ], scene);
    axisX.color = new BABYLON.Color3(1, 0, 0);

    let xChar = makeTextPlane("X", "red", size / 8);
    xChar.position = new BABYLON.Vector3(0.9 * size, -0.05 * size, 0);
    xChar.parent = axisX;

    let axisY = BABYLON.Mesh.CreateLines("axisY", [
        new BABYLON.Vector3.Zero(),
        new BABYLON.Vector3(0, size, 0),
        new BABYLON.Vector3( -0.05 * size, size * 0.95, 0),
        new BABYLON.Vector3(0, size, 0),
        new BABYLON.Vector3( 0.05 * size, size * 0.95, 0)
    ], scene);
    axisY.color = new BABYLON.Color3(0, 1, 0);

    let yChar = makeTextPlane("Y", "green", size / 8);
    yChar.position = new BABYLON.Vector3(0, 0.9 * size, -0.05 * size);
    yChar.parent = axisY;

    let axisZ = BABYLON.Mesh.CreateLines("axisZ", [
        new BABYLON.Vector3.Zero(),
        new BABYLON.Vector3(0, 0, size),
        new BABYLON.Vector3( 0 , -0.05 * size, size * 0.95),
        new BABYLON.Vector3(0, 0, size),
        new BABYLON.Vector3( 0, 0.05 * size, size * 0.95)
    ], scene);
    axisZ.color = new BABYLON.Color3(0, 0, 1);

    let zChar = makeTextPlane("Z", "blue", size / 8);
    zChar.position = new BABYLON.Vector3(0, 0.05 * size, 0.9 * size);
    zChar.parent = axisZ;

    return [axisX, axisY, axisZ];
}

function createScene1(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 4, Math.PI / 3, 2.75, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule = BABYLON.MeshBuilder.CreateCapsule("capsule", {orientation: new BABYLON.Vector3(1, 0, 0)}, scene);
    capsule.material = mat;
    let axis_origin = createLocalAxes(1, scene);
    axis_origin.parent = capsule;
    
    return scene;
};

var scene1 = createScene1(canvas1, engine1);

engine1.runRenderLoop(function(){
    scene1.render();
});

window.addEventListener("resize", function(){
    engine1.resize();
});
</script>

<canvas id="renderCanvas1"></canvas>
Figure 2. The orientation property is set on the x-axis.

Subdivisions

The subdivision property specifies the number of segments in the cylinder portion of the capsule parallel to the orientation. The default value is 2.

<script>
var canvas2 = document.getElementById("renderCanvas2");
var engine2 = new BABYLON.Engine(canvas2, true);

function createScene2(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);
    mat.wireframe = true;

    let capsule1 = BABYLON.MeshBuilder.CreateCapsule("capsule1", {subdivisions: 1}, scene);
    capsule1.material = mat;
    capsule1.position = new BABYLON.Vector3(-3, 0, 0);
    
    let capsule2 = BABYLON.MeshBuilder.CreateCapsule("capsule2", {subdivisions: 2}, scene);
    capsule2.material = mat;
    capsule2.position = new BABYLON.Vector3(-1, 0, 0);
    
    let capsule3 = BABYLON.MeshBuilder.CreateCapsule("capsule3", {subdivisions: 3}, scene);
    capsule3.material = mat;
    capsule3.position = new BABYLON.Vector3(1, 0, 0);
    
    let capsule4 = BABYLON.MeshBuilder.CreateCapsule("capsule4", {subdivisions: 4}, scene);
    capsule4.material = mat;
    capsule4.position = new BABYLON.Vector3(3, 0, 0);
    
    return scene;
};

var scene2 = createScene2(canvas2, engine2);

engine2.runRenderLoop(function(){
    scene2.render();
});

window.addEventListener("resize", function(){
    engine2.resize();
});
</script>

<canvas id="renderCanvas2"></canvas>
Figure 3. From left to right, the subdivisions property is set to 1, 2, 3, and 4.

Tessellation

The tessellation property specifies the number of sides on the entire capsule. The more sides we have, the more cylindrical the capsule will be. The default value is 16.

<script>
var canvas3 = document.getElementById("renderCanvas3");
var engine3 = new BABYLON.Engine(canvas3, true);

function createScene3(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 6, 2, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule = BABYLON.MeshBuilder.CreateCapsule("capsule", {tessellation: 3}, scene);
    capsule.material = mat;
    
    return scene;
};

var scene3 = createScene3(canvas3, engine3);

engine3.runRenderLoop(function(){
    scene3.render();
});

window.addEventListener("resize", function(){
    engine3.resize();
});
</script>

<canvas id="renderCanvas3"></canvas>
Figure 4. The tessellation property is set to 3.

Height

The height property specifies the length of the capsule from one cap to the other cap. The default value is 1.

<script>
var canvas4 = document.getElementById("renderCanvas4");
var engine4 = new BABYLON.Engine(canvas4, true);

function createScene4(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 4, Math.PI / 4, 3, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule = BABYLON.MeshBuilder.CreateCapsule("capsule", {height: 2}, scene);
    capsule.material = mat;
    
    return scene;
};

var scene4 = createScene4(canvas4, engine4);

engine4.runRenderLoop(function(){
    scene4.render();
});

window.addEventListener("resize", function(){
    engine4.resize();
});
</script>

<canvas id="renderCanvas4"></canvas>
Figure 5. The height property is set to 2.

Radius

The radius property specifies the width of the entire capsule from one side to the other side. The default value is 0.25.

<script>
var canvas5 = document.getElementById("renderCanvas5");
var engine5 = new BABYLON.Engine(canvas5, true);

function createScene5(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 4, Math.PI / 2, 6, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule = BABYLON.MeshBuilder.CreateCapsule("capsule", {height: 4, radius: 2.0001}, scene);
    capsule.material = mat;
    
    return scene;
};

var scene5 = createScene5(canvas5, engine5);

engine5.runRenderLoop(function(){
    scene5.render();
});

window.addEventListener("resize", function(){
    engine5.resize();
});
</script>

<canvas id="renderCanvas5"></canvas>
Figure 6. The radius property is set to 2.0001 to make the capsule a sphere.

Notice in figure 6 that when the radius property is close to half of the height property, our capsule turns into a sphere. However, should we set the radius property to exactly half of the height, we will get an artifact.

CapSubdivisions

The capSubdivisions property specifies the number of segments that make up the caps on the ends of the capsule mesh parallel to the orientation. The default value is 6.

<script>
var canvas6 = document.getElementById("renderCanvas6");
var engine6 = new BABYLON.Engine(canvas6, true);

function createScene6(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);
    mat.wireframe = true;

    let capsule1 = BABYLON.MeshBuilder.CreateCapsule("capsule1", {capSubdivisions: 1}, scene);
    capsule1.material = mat;
    capsule1.position = new BABYLON.Vector3(-3, 0, 0);
    
    let capsule2 = BABYLON.MeshBuilder.CreateCapsule("capsule2", {capSubdivisions: 2}, scene);
    capsule2.material = mat;
    capsule2.position = new BABYLON.Vector3(-1, 0, 0);
    
    let capsule3 = BABYLON.MeshBuilder.CreateCapsule("capsule3", {capSubdivisions: 3}, scene);
    capsule3.material = mat;
    capsule3.position = new BABYLON.Vector3(1, 0, 0);
    
    let capsule4 = BABYLON.MeshBuilder.CreateCapsule("capsule4", {capSubdivisions: 4}, scene);
    capsule4.material = mat;
    capsule4.position = new BABYLON.Vector3(3, 0, 0);
    
    return scene;
};

var scene6 = createScene6(canvas6, engine6);

engine6.runRenderLoop(function(){
    scene6.render();
});

window.addEventListener("resize", function(){
    engine6.resize();
});
</script>

<canvas id="renderCanvas6"></canvas>
Figure 7. From left to right, the capSubdivisions property is set to 1, 2, 3, and 4.

RadiusTop and RadiusBottom

The radiusTop and radiusBottom properties overwrite the radius property for the top half and bottom half of the capsule, respectively. These properties defaults to the radius property value.

<script>
var canvas7 = document.getElementById("renderCanvas7");
var engine7 = new BABYLON.Engine(canvas7, true);

function createScene7(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 3, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);

    let capsule1 = BABYLON.MeshBuilder.CreateCapsule("capsule1", {radiusTop: -0.5}, scene);
    capsule1.material = mat;
    capsule1.position = new BABYLON.Vector3(-1, 0, 0);
    
    let capsule2 = BABYLON.MeshBuilder.CreateCapsule("capsule2", {radiusBottom: -0.5}, scene);
    capsule2.material = mat;
    capsule2.position = new BABYLON.Vector3(1, 0, 0);
    
    return scene;
};

var scene7 = createScene7(canvas7, engine7);

engine7.runRenderLoop(function(){
    scene7.render();
});

window.addEventListener("resize", function(){
    engine7.resize();
});
</script>

<canvas id="renderCanvas7"></canvas>
Figure 8. The left-hand capsule has property radiusTop set to -0.5. The right-hand capsule has property radiusBottom set to -0.5.

TopCapSubdivisions and BottomCapSubdivisions

The topCapSubdivisions and bottomCapSubdivisions properties overwrite the capSubdivisions property for the top cap and bottom cap on the capsule, respectively. These properties defaults to the capSubdivisions property value.

TopCapSubdivisions

<script>
var canvas8 = document.getElementById("renderCanvas8");
var engine8 = new BABYLON.Engine(canvas8, true);

function createScene8(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);
    mat.wireframe = true;

    let capsule1 = BABYLON.MeshBuilder.CreateCapsule("capsule1", {topCapSubdivisions: 1}, scene);
    capsule1.material = mat;
    capsule1.position = new BABYLON.Vector3(-3, 0, 0);
    
    let capsule2 = BABYLON.MeshBuilder.CreateCapsule("capsule2", {topCapSubdivisions: 2}, scene);
    capsule2.material = mat;
    capsule2.position = new BABYLON.Vector3(-1, 0, 0);
    
    let capsule3 = BABYLON.MeshBuilder.CreateCapsule("capsule3", {topCapSubdivisions: 3}, scene);
    capsule3.material = mat;
    capsule3.position = new BABYLON.Vector3(1, 0, 0);
    
    let capsule4 = BABYLON.MeshBuilder.CreateCapsule("capsule4", {topCapSubdivisions: 4}, scene);
    capsule4.material = mat;
    capsule4.position = new BABYLON.Vector3(3, 0, 0);
    
    return scene;
};

var scene8 = createScene8(canvas8, engine8);

engine8.runRenderLoop(function(){
    scene8.render();
});

window.addEventListener("resize", function(){
    engine8.resize();
});
</script>

<canvas id="renderCanvas8"></canvas>
Figure 9. From left to right, the topCapSubdivisions property is set to 1, 2, 3, and 4.

BottomCapSubdivisions

<script>
var canvas9 = document.getElementById("renderCanvas9");
var engine9 = new BABYLON.Engine(canvas9, true);

function createScene9(canvas, engine){
    let scene = new BABYLON.Scene(engine);
    scene.clearColor = new BABYLON.Color3(1, 1, 1);
    let camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 5, BABYLON.Vector3.Zero(), scene);
    camera.attachControl(canvas, true);
    let light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);

    let mat = new BABYLON.StandardMaterial("mat", scene);
    mat.diffuseColor = new BABYLON.Color3(0, 1, 0);
    mat.wireframe = true;

    let capsule1 = BABYLON.MeshBuilder.CreateCapsule("capsule1", {bottomCapSubdivisions: 1}, scene);
    capsule1.material = mat;
    capsule1.position = new BABYLON.Vector3(-3, 0, 0);
    
    let capsule2 = BABYLON.MeshBuilder.CreateCapsule("capsule2", {bottomCapSubdivisions: 2}, scene);
    capsule2.material = mat;
    capsule2.position = new BABYLON.Vector3(-1, 0, 0);
    
    let capsule3 = BABYLON.MeshBuilder.CreateCapsule("capsule3", {bottomCapSubdivisions: 3}, scene);
    capsule3.material = mat;
    capsule3.position = new BABYLON.Vector3(1, 0, 0);
    
    let capsule4 = BABYLON.MeshBuilder.CreateCapsule("capsule4", {bottomCapSubdivisions: 4}, scene);
    capsule4.material = mat;
    capsule4.position = new BABYLON.Vector3(3, 0, 0);
    
    return scene;
};

var scene9 = createScene9(canvas9, engine9);

engine9.runRenderLoop(function(){
    scene9.render();
});

window.addEventListener("resize", function(){
    engine9.resize();
});
</script>

<canvas id="renderCanvas9"></canvas>
Figure 10. From left to right, the bottomCapSubdivisions property is set to 1, 2, 3, and 4.

References