First, for an overview of the overall feature and its architecture you can read this documentation
The overview Home Page is also a good place to learn the many different concepts.
The Canvas2D is the answer to those who need to display 2D content above a 3D Scene (in game UI), which is called a ScreenSpace Canvas or directly inside the Scene as a rectangle containing the Canvas' content, which is called World Space Canvas.
This is a Small 2D Engine, based on babylon.js core features, giving you the opportunity to finally manage 2D content in your creations.
This feature was designed to be as fast as possible and yet flexible, future will tell if these target will be met, but so far we are on the right tracks! :)
The main class, is a rectangle that display 2D content.
A Canvas can be represented in:
ScreenSpaceCanvas2D
class is used.WorldSpaceCanvas2D
class is used.Both of these classes are simple wrappers to ease the construction time, but all the logic is implemented in the Canvas2D
class, so we'll often refer to this class instead of the two others.
Acts as a container, a new frame of reference that contains children primitives. Note that any kind of types involved in the Canvas2D feature can have children, it's not an exclusive feature of the Group2D. In order to optimize performances, the content of a Group2D can be cached into a bitmap to save rendering time as the expense of texture memory holding the content.
A Shape2D is a parametric form which is drawn using brushes, one for the border and another one for the content (also called fill). There are three types of Shapes so far: Rectangle2D, Ellipse2D and Lines2D.
To display a portion of a texture.
To display some text.
The simplest starting point would be created a ScreenSpace Canvas2D with a "Hello World!" text, here we go:
var canvas = new BABYLON.ScreenSpaceCanvas2D(scene, {
id: "ScreenCanvas",
size: new BABYLON.Size(300, 100),
backgroundFill: "#4040408F",
backgroundRoundRadius: 50,
children: [
new BABYLON.Text2D("Hello World!", {
id: "text",
marginAlignment: "h: center, v:center",
fontName: "20pt Arial",
})
]
});
See it live in this playground -
The code is pretty self explanatory, but let's run through it:
children
settings array to create children primitive in a cascading fashion.ScreenSpaceCanvas2D
type and create an instance, the default position of (0,0) will be used, with a width of 300 and a height of 100. The content won't be cached, hence redraw at every render of the scene as the default caching strategy is CACHESTRATEGY_DONTCACHE
.children
array a Text2D
primitive which will be centered both horizontally and vertically to its parent (the Canvas), with a font 20pt Arial
, and the default color (white).Let's get something a little bit more complicated:
var canvas = new BABYLON.ScreenSpaceCanvas2D(scene,
{
id: "ScreenCanvas", size: new BABYLON.Size(500, 500),
backgroundFill: "#C0C0C040", backgroundRoundRadius: 50
});
var rect = new BABYLON.Rectangle2D({
id: "mainRect", parent: canvas, x: 200, y: 200, width: 100, height: 100,
fill: "#404080FF", border: "#A040A0D0, #FFFFFFFF", borderThickness: 10,
roundRadius: 10,
children:
[
new BABYLON.Rectangle2D(
{
id: "insideRect", marginAlignment: "v: center, h: center",
width: 40, height: 40, fill: "#FAFF75FF", roundRadius: 10
})
]});
var timerId = setInterval(function () {
if (rect.isDisposed) {
clearInterval(timerId);
return;
}
rect.rotation += 0.003;
}, 10);
See it live in this playground -
Explanations:
parent
settings to link it to the Canvas itself, it's called "mainRect" and is centered in the Canvas with the position 200,200 (position is always from the bottom/left corner of the primitive relative to the bottom/left corner of its parent). children
array. We use alignment to position it at the center of its parent and with a size of 40,40. We use a solid color brush for the fill content and a custom round radius.You will notice when you run the sample that both rectangles are rotating, which is as expected because "insideRect" is a children of "mainRect", hence inheriting of the animated transformation.
Now let's try the second type of Canvas: the World Space one, as opposed to the Screen Space one, World Space Canvas are part of the 3D Scene, they're displayed in a rectangle, as a regular scene node.
var canvas = new BABYLON.WorldSpaceCanvas2D(scene, new BABYLON.Size(100, 100), {
id: "WorldSpaceCanvas",
worldPosition: new BABYLON.Vector3(0, 0, 0),
worldRotation: BABYLON.Quaternion.RotationYawPitchRoll(Math.PI / 4, Math.PI / 4, 0),
renderScaleFactor: 8,
enableInteraction: true,
backgroundFill: "#C0C0C040",
backgroundRoundRadius: 80,
children: [
new BABYLON.Text2D("World Space Canvas", { fontName: "30pt Arial", marginAlignment: "h: center, v: bottom" })
]
});
// Create spinning rectangles
var rect = new BABYLON.Rectangle2D(
{ parent: canvas, x: 300, y: 300, width: 200, height: 200, fill: null,
border: BABYLON.Canvas2D.GetGradientColorBrush(new BABYLON.Color4(0.9, 0.3, 0.9, 1), new BABYLON.Color4(1.0, 1.0, 1.0, 1)),
borderThickness: 20,
children:
[
new BABYLON.Rectangle2D(
{ parent: rect, width: 80, height: 80, marginAlignment: "h: center, v: center",
fill: "#0040F0FF", roundRadius: 20 })
]});
// Create the "click me!" button
var buttonRect = new BABYLON.Rectangle2D(
{ parent: canvas, id: "button", x: 100, y: 100, width: 200, height: 80, fill: "#40C040FF",
roundRadius: 10,
children:
[
new BABYLON.Text2D("Click Me!", { fontName: "30pt Arial", marginAlignment: "h: center, v: center" })
]});
// Create the "Awesome!" button
var button2Rect = new BABYLON.Rectangle2D(
{ parent: canvas, id: "button2", x: 420, y: 100, width: 200, height: 80, fill: "#4040C0FF",
roundRadius: 10, isVisible: false,
children:
[
new BABYLON.Text2D("Awesome!", { fontName: "30pt Arial", marginAlignment: "h: center, v: center" })
]});
// Add an observable to the "Click me!" button, watch for click the display/hide the second button
buttonRect.pointerEventObservable.add(function (d, s) {
button2Rect.levelVisible = !button2Rect.levelVisible;
}, BABYLON.PrimitivePointerInfo.PointerUp);
// Animate the two rectangles
var timerId = setInterval(function () {
if (rect.isDisposed) {
clearInterval(timerId);
return;
}
rect.rotation += 0.01;
}, 10);
See it live in this playground -
This time we create a Canvas that will be present in the scene and not above, its position is 0,0,0, the rotation is built from yaw/pitch/roll construct, its scene size is 100,100 but the Canvas cached bitmap is scaled 8 times (to achieve a much better rendering quality).
We also create two buttons and add an observable on the first one to display/hide the second one.
The canvas
object is not a Scene node, to access the actual SceneNode that positions the Canvas and renders it you have to access the worldSpaceCanvasNode
property of the Canvas2D
class. This will return you a Node
based instance that you can manipulate to change how the Canvas behave in the 3D Scene.
Just go to the Canvas2D Home Page. All playgrounds are referenced at the end of the document.