Interactive 2D graphics engine
Arbo is work-in-progress real-time interactive 2D graphics engine based on SDF and ray tracing. Scene is composed from interactive reusable parts, defined as mathematical transformations over just two primitives.
Still in early experimental phase. Development is done on Linux & Android using the LÖVE framework for Lua.
The development is discontinued for now, as I focus on other projects.
This project is experiment in creating a new technique for interactive art.
Pixel art is tedious to make at high resolution and it looks blocky at low resolution. Mixing low and high resolution assets looks horrible. It’s also completely static; animation is done by switching between static images.
High resolution bitmap art is very unforgiving to artist. It’s not possible to go back in history and modify single stroke while keeping the rest of work as it is. The resulting image is static and ‘dumb’. Just like pixel art, high resolution art represents 2D scene that’s been sampled within area of canvas. By converting shapes into image we have lost all information about shape except color at location of pixels.
Vector art is ‘smarter’ in sense that you can compose the scene from shapes and objects and manipulate them later. Vector art can be dynamically manipulated to create animations. The main downside is that polygons are still sampled shapes. The polygon with 100 points will look sharp and well defined only until certain zoom level. While the design starts with well-defined primitives (square, circle…), by doing few manipulations (cut, combine) those primitives are converted to dumb polygons and it’s not possible to revert this operation later. In current vector art authoring tools it is also difficult to work with infinitely large shapes (ground and sky, ray of sun), smart instancing (mirrors, shadows, arrays) or recursively defined shapes (trees, fractals). Although vector art can be dynamic, there’s little support for it in tools and in most cases it’s converted and displayed as static image.
This project explores another approach inspired by signed distance fields and constructive geometry. A dynamic scene is built from small number of compose-able primitives and transformations. The benefits should include:
One additional goal for project is to have full content authoring platform on mobile phone with touch-based interface. It makes more sense to build a tool that can be used while away from computer.
A scene is hierarchical tree composed of primitives and transformations over primitives. It is expressed using nested tables in Lua syntax:
scene = {transform-name, {transform-parameters}, {sub-scene}}
The sub-scene follows the same nested structure, until primitives are reached. There are currently two primitives:
simplex is primitive that implements simplex noise. It produces pseudo-random bloby shapes that are predictable in size and distribution, but not predictable in exact shape.
The edge and simplex represent two approaches to scene modelling. The edge is used when we want to manually produce a well defined shape - a flower, sun, a building, an animal…
The simplex allows us to add random patterns for vague elements that would be too hard to compose exactly - clouds, bush, stars, animal stripes, surface irregularities…
Both edge and simplex produce a shape - they can be rendered on screen, or manipulated by shape transformations that also a produce shape.
Current transformations include:
{position, {dx, dy, rot, sx, sy}, shape}
{wrap, yexp, shape}
{negate, shape}
{mirror, shape}
{combine, shape1, shape2, ...}
{cut, shape1, shape2, ...}
smooth softly melds one shape into another, or substracts them if softness is negative
{smooth, softness, shape1, shape2}
tint sets the color of drawn shape, using HSL color model
{tint, {hue, saturation, lightness}, shape}
{memo, precision-setting, shape}
The scene is rendered similar to 3D ray-tracing technique. We start with a blank canvas that will hold the resulting image.
This method is done few thousand times per second. The canvas is never cleared, it’s constantly overdrawn with new rays.
As scene grows in complexity, it takes more and more time to calculate value for single ray. Stroke size can be increased to get rough scene outline, and then lowered to produce finer details.
This part is still under construction.
The scene is defined as tree structure, which is just like AST (abstract syntax tree) and lisp’s S-expressions. The scene definition is both data and code. It should be possible for scene to contain instructions to modify itself.
User should specify how parts of the scene should look like in different contexts. Then depending on current context the engine could interpolate the values.
Current sample scenes execute the Lua code that’s used to simulate real-time changes. There’s also basic support for passing environment table down the tree, that can be referenced in geometry instead of using constants.
Under construction, to be completely re-imagined. Current iteration already has many features to navigate the scene tree and edit numerical values on the fly.
Missing features are changing between scenes, reusing same node in different parts of trees (and navigating between contexts of reused nodes), constructing reflective geometry and editing interactive nodes.
Use one finger dragging to navigate through tree.
When on tint
node use two-finger swiping to modify color:
swipe left/right to change hue
swipe up-left/down-right to change saturation
swipe up-right/down-left to change lightness
When on position
node, use two finger pinch gesture to move/rotate/scale content.
When constant number is selected, use rotating gesture with two fingers to increase/decrease the value.
While navigating the scene tree, icons will show up if they are relevant in current context. Icons don’t have any tooltips and not all are intuitive. Work in progress…
Grab interpreter from LÖVE website and use it to execute main.lua
. Currently requires screen with multi-touch to access most features (doesn’t work with mouse).
As for Android, it’s still too early to start packaging & distributing the APK. To run it on phone/tablet follow these instructions:
grab v0.11 of interpreter for Android from here
place content of this repository into /sdcard/lovegame
so that main.lua
ends up on /sdcard/lovegame/main.lua
path
For development, the deploying can be automated with adb push
and executing can be done using command:
adb shell am start -S -n "org.love2d.android/.GameActivity" -d "file:///sdcard/lovegame/main.lua"
Some ideas for future features:
Below are some scenes created to develop and test features of renderer. They look more alive in renderer than as static images.
Tree defined as recursive geometry - a tree is composed of a single branch and few smaller trees on top.
Same tree in more complex night scene with reflected geometry and clipping.
Sunset scene that dynamically changes location and color of shapes.
Flying above earth. Both clouds and continents are simplex noise.
Demonstration of current editor, both navigating scene tree and changing numerical values to modify colors on the fly.
Camera manipulation
A forest scene modeled with manipulated simplex noise
A moonlit lake scene
Landscape scene with varying opacity and size of strokes
Sunset over snowy mountain
Parallax effect built by linked transform operations
Snow-covered pine trees