Understanding DragonRuby Render Targets
Render targets are a mythical unicorn in DragonRuby
So before we continue on with use cases and why render targets are great, lets look at the syntax (because I always forget) for render targets.
There is a different syntax using args.render_target(:target_name)
, but we’re not going to really cover that here.
Thats it! You made a render target! What the above does is essentially tell DragonRuby to “create a ‘virtual canvas’, 100px by 100px, make its background color black, and cache the result.”
Now, this doesn’t do anything by itself. If you’re familiar with “pointers” from C, we essentially have created a “pointer” to the render target. But in order to actually render the render target (have we said “render” enough yet?) we actually have to create a “sprite” and make its :path
point to the render target.
Like so:
In particular, the magic happens on line 15 where we pass the :black_box
symbol as a path
for the sprite.
Now we can go further and do things such as creating multiple sprites using the render target, scale the sprite, angle the sprite, and perform all sorts of transforms. So here is what happens when I start overlaying them with different transforms.
Now this is pretty basic so far, and you could accomplish all of this without render targets. This is more showing basic syntax and how render targets are used.
Its also worth noting render targets have special behavior different from that of the standard screen.
From this doc example: https://docs.dragonruby.org/#/samples/advanced-rendering?id=render-target-noclear-mainrb
Note that you can NOT opt to skip clearing the screen, only render targets.
The screen clears every frame; double-buffering would prevent correct updates between frames.
This means render targets have special behavior where as typical DragonRuby rendering clears the screen on every tick, you can actually opt to have DragonRuby not clear the render target. To access this behavior, you can use the following syntax:
args.outputs[:my_render_target].clear_before_render = false
Extra word of caution on caching
Every call to args.outputs[:render_target]
creates a new render target instance for the current tick
(frame), thus clearing out any cached render targets from previous ticks / frames. You can see this in action below.
In fact, thanks to Amir, I learned args.outputs[:render_target]
is essentially an alias for args.render_target(:render_target)
.
From Amir:
args.outputs[:render_target]
queues a render target for creation: https://github.com/DragonRuby/dragonruby-game-toolkit-contrib/blob/df9e3bb7f2fc873eceac9bec77389bc36a0d7280/dragon/outputs.rb#L850
So be careful!
Other things that will “clear the cache”
The
args.outputs
structure renders to the screen. You can render to a texture/virtual canvas using args.outputs[SYMBOL]. What ever primitives are sent to the virtual canvas are cached and reused (the cache is invalidated whenever you render to virtual canvas).https://docs.dragonruby.org/#/api/outputs?id=render-targets-operator
So in other words, anytime you do args.outputs[:render_target].sprites << {}
you will clear the cache and DragonRuby will re-render the render target. Same for any labels, borders, primitives, etc.
Go forth and (ab)use render targets!
Render targets have many, many use cases. Too many to cover here, and way too much to write. But a short list is roughly: lighting, blending, scaling, cameras, caching, animations.
For a full rundown of how versatile render target are, check out the Advanced Rendering
As an extra bonus, there are even performance improvements that can happen when using and moving a large number of primitives at once by using a render target. This is how the Camera example works for example. It uses :scene
symbol as the render target and allows you to move many sprites at once without tanking performance.
Anyways, this is quick post about the beauty of render targets and the cool tricks they enable and problems they help solve.