Tutorial 14: Canvas
In this tutorial you will learn how to use the canvas entity.
Before starting this tutorial be sure to setup an empty project with the Setup Tutorial.
That's it. :)
Now that you know about the canvas, time to learn how to integrate physics into ness-engine!
Ness::CanvasPtr canvas = node->create_canvas(name, size);
// create root node. everything we want to rotate must be under this node
Ness::NodePtr rootNode = scene->create_node();
// create the canvas
int canvasSize = renderer.get_screen_size().get_length();
Ness::CanvasPtr canvas = scene->create_canvas("whole_screen", Ness::Sizei(canvasSize, canvasSize)); canvas->set_anchor(Ness::Point::HALF);
// set the node rendering target
// now add your stuff under rootNode and to rotate the entire screen use canvas->set_rotation()
What is the canvas entity?
Rendering on texture lets you create or change textures on-the-fly, using the rendering tools ness-engine provides.
The canvas entity is a very important object you can use for special effects. basically the canvas is a sprite, but instead of using existing or loaded texture it creates an empty texture you can render on.
What is it good for?
The most useful usage of the canvas is for post-rendering effects: you can create an empty canvas in the size of the screen, render everything on it, and in the end render the canvas with transformations and special effects. for example, you can use this technique to rotate the entire screen, mirror it, or tilt the color of everything.
You can set the render target for every scene node by providing texture:
or a canvas entity:
once you set rendering target, everything under this node will render itself on the given target instead of on the screen. if the node has a son node with a different rendering target, the son node and his sons will render on the more specific target.
note that you can choose any texture to be a rendering target.
Creating a canvas
To create a canvas with an empty texture, use the following function:
parameter name is the name to give to the new texture we create. must be unique.
parameter size is a Ness::Sizei() instance with the size of the texture to create. if you don't provide this parameter, it will create an empty texture in the size of the renderer screen.
once a canvas is created it behaves just like a sprite. the only limit you need to remember about the canvas is to never put a canvas in the same node that you set it as the rendering target. if you do, it will just render everything on the canvas and then render the canvas on itself, so nothing will appear on the screen.
Rotating the screen
As mentioned, you can use a canvas to rotate the entire screen. to do so, follow these steps:
- create a canvas with size equals to the distance between the top-left corner of the screen to the bottom-right corner of the screen. this is because when the screen rotates you need the canvas to be big enough to cover everything.
- set the canvas anchor to be center, and place the canvas at the middle of the screen.
- create a root node and put everything under it. set the canvas as the rendering target of that node.
- make sure your canvas is in a different node or scene, and now you can simply set it's rotation.
you code should look something like this:
Rendering target as screen bounderies
Remember from previous tutorials that everything out of screen will not be rendered? it's important to understand that "out of screen" actually means "out of current render target bounderies", be it the screen or a texture. because of that, it's important to set the size of the canvas correctly - too big and you will render useless parts, too small and you will miss renderings.
The Canvas entity comes with a built-in masking functionality that let you apply shapes with constant alpha channels on your canvas. for masks we use black and white textures where the black parts will be visible and the white parts will be transparent.
You can use this feature to create effects like round minimap or portal-like effects that show parts from the other side. for example, take a look at the following screenshot from a ness-engine test project:
See the round minimap at the top-left corner? it was achieved with canvas & masking. in this example the map is just a mockup texture, I used the following map and mask:
Note however that using masks have some limitations:
whenever a mask is applied, Canvas blending will not work (blending will be based on the mask, additive/modulate blending effects will not work).
if you use texture with alpha channels as the mask, it will make the result be transparent at the bright areas in addition to the mask. so be sure to use BMP formats with 24 bits or less. (read ahead to understand why this happens).
What happens if I use mask that is not black and white?
If you are curious about how masking works, it basically goes like this:
the inverted mask is rendered on the scene with additive blend at the area you are about to render the canvas on. this will create a white silhouette at the shape of the mask.
the mask will be rendered on the canvas itself with additive effect, meaning the white parts of the mask will also be white at the canvas.
the canvas will be rendered on scene with modulte effect, meanning the white parts will be transparent.
so what will happen if we use a colorful mask? something like this:
But in real usage the idea is that the minimap is by-far larger then the mask, and as you advance in the level it reveals different parts of the map based on your position. or as an alternative, the map doesn't have to be a pre-baked texture and can be generated in runtime from the level itself.
Any black and white texture can be used as a mask, to apply a mask on a canvas use the following command: