Running on OPENRNDR
What makes OPENRNDR different from other frameworks for creative coding?
This story is part of a series of case studies related to the open source framework for creative coding OPENRNDR, written in Kotlin for the Java Virtual Machine. OPENRNDR simplifies writing real-time audio-visual interactive software. The framework is designed and developed with two goals in mind: prototyping and the development of robust performant audio-visual applications.
The development of OPENRNDR was initially started in 2010 at LUSTlab under the name RNDR, with the idea to create an in-house framework that was versatile enough to sketch in, but at the same time robust enough to deliver production-quality interactive media installations, that you know will also run without worries in a few years from now. It takes the creative mind-set of a designer or artist, and combines that with the power of production-grade software. As we could not find this in existing software, we decided to develop this ourselves. We are convinced that there are many more people out there that crave for the same. The framework is built around hardware accelerated rendering and focuses on simple and safe to use APIs for rendering.
Which framework fits your way of working?
Choosing the right framework is a difficult and very personal thing. As all frameworks have a slightly different approach, we try to outline some differences and similarities with other, existing open source frameworks and their respective pros and cons in the field of creative coding. As OPENRNDR uses the imperative programming paradigm, we compare it mainly with other imperative-based frameworks, as Processing and openFrameworks, but there are also a few declarative frameworks which use a node- or flow-based metaphor, as VVVV, MaxMSP, Pure Data, and TouchDesigner.
OPENRNDR is made with creative coders in mind. Creative coding is approaching computing as a mechanical machine instead of a mathematical formality. A machine that can process data (and what looks like data) with precise and predictable outcome if operated in the intended way. Creative coding is a necessity in the creation of exciting interactive experiences.
OPENRNDR and Processing
While both Processing and OPENRNDR are written to use the Java Virtual Machine, OPENRNDR’s approach is to utilise the existing Kotlin and Java development tools whereas Processing has built their own. Processing’s tooling is easy to use but it does not integrate well with existing infrastructures, making it harder to use existing libraries that are not specifically written to be used with Processing. When you are new to creative coding, Processing is probably a good place to start, as there is already a large community and it is taught in many classrooms.
Processing provides simplified APIs to its users, which work great in the context of education and prototyping but may be disadvantageous outside of that scope. We felt that the simplified APIs burdens the user with program complexity when working on large projects.
In contrast, OPENRNDR’s APIs are designed to embrace Kotlin’s advanced functionality while still being easy to use. It fully embraces its existing infrastructure of (open source) libraries, editors, debuggers and build tools. The bottom-line is, we feel that Processing is less suitable for a production context.
OPENRNDR and openFrameworks
OpenFrameworks is designed to work as a general purpose glue, and wraps together many commonly used libraries. OpenFrameworks is written in C++ and targeted at very advanced users. The advertised benefit of developing in native C++ over using the JVM is the speed of execution. While that statement holds in general, in the context of visual computing, in which most of the work takes place on the graphics adapter, this benefit is not as strongly apparent in most cases. Developing in C++ comes with complexities that do not exist on the JVM platform.
Please be aware that OPENRNDR is still a young framework, and lots of features and improvements are implemented on a weekly basis. Lets run through some examples of unique features.
On guide.openrndr.org you will find an extensive documentation that should help you get up to speed with OPENRNDR. The guide is written on a per topic basis and each topic comes with a concise explanation and example source code. The guide is still work in progress and will be updated on a regular basis.
Now you may be wondering what an OPENRNDR project looks like.
OPENRNDR is mostly a software library and as such we don’t provide tools for editing or building your software. You are free to choose your own tools in which you would like to code your projects. We recommend using the freely available IntelliJ Idea Community edition.
OPENRNDR projects are Gradle based. Gradle is a tool that takes care of compiling and building Java and Kotlin software. Gradle can use the Maven package manager to resolve project dependencies. To start an OPENRNDR project all we have to do is tell Gradle to add the OPENRNDR library as a dependency.
Now that that is done we can write our very first OPENRNDR program. This will look roughly like this. Those who have used Processing may be familiar with the structure.
What happens here is we create a SimpleProgram class that inherits from OPENRNDR’s program.
In the draw we clear the background, set the fill to pink and the stroke to null (effectively no stroke). And we draw a circle at the center of the screen. All of this happens using the drawer object.
Here is, just to give you an idea, a shortened overview of what the drawer object can do. Probably its the most used OPENRNDR component, but there are many more components offered and documented in the guide.
So yes, up till now nothing really new and groundbreaking, huh? But you may be asking, I don’t really like circles, I’m more into rectangles? Good news, look no further!
Everything is a shader
Most functionality in the OPENRNDR drawer uses vertex and fragment shaders in its internals. We think that rewriting that functionality just to make it look different is considered wasteful. To prevent rewriting existing drawing functionality, OPENRNDR uses a form of shader templating with which the default appearance can be changed easily. In OPENRNDR this is called shade styles.
Here is a very simple example of shadeStyles. It is drawing the rectangle in red overriding the fill color (by setting x_fill) in the fragmentTransform.
We assign a shadeStyle that has a fragment transform. The language inside the fragmentTransform is actually a snippet of GLSL which stands for OpenGL Shading Language, a high-level shading language with a syntax based on the C-programming language.
Admittedly, that red square wasn’t that special either, but it is just to give an idea you can apply any set of functions on the rectangle. Here we show a slightly more complex transformation that draws a radially animating gradient.
Using the parameter interface additional data can be passed to the shade style. In the above example we use a time parameter to drive the animation.
Shade styles can also be used to apply transformations to text. Here we see a simple cutting operation based on a function of character index, position and time.
The previous cutting transform is applied repeatedly and an extra offset parameter is added to create this more interesting typographic effect.
Render targets & post processing
Another thing that is really easy in OPENRNDR is the ability to draw to a render target –which is essentially an offscreen image. By rendering to a render target we create the possibility to apply filters, –or post processing.
This shows how to create a render target and draw a circle on the render target. The render target is then drawn to the screen. This looks exactly like we would be drawing a circle on the screen directly.
But now that the circle is on a separate render target. We can take out the underlying image of the render target and apply filtering to it. In this case we use one of the built-in blur effects to blur the circle.
We can take our typographic shade style example from before and apply the blur there too.
All of this is performed using GPU hardware acceleration and none of this required using complex/lowlevel APIs like OpenGL.