This tutorial shows you how to draw and position 3D text in a jit.window
object using the jit.gl.text3d
objects. Along the way, we will cover the basics of drawing OpenGL graphics using the jit.gl.render
object is one of the many Jitter OpenGL drawing objects that work in conjunction with the jit.gl.render
object. OpenGL is a cross-platform standard for drawing 2D and 3D graphics, designed to describe images so that they can be drawn by graphics coprocessors. These coprocessors, also known Graphics Processor Units or GPUs, speed up drawing operations enormously, allowing complex scenes made of textured polygons to be animated in real time. OpenGL graphics can help you create faster visual displays or interfaces without bogging down your computer’s CPU.
In the lower left of the patch, there is a jit.window
object named . This window will be the destination for our OpenGL drawing.
• Click on the toggle
labeled Start Rendering
The toggle starts the qmetro
object,which sends messages to a trigger
object. For each received at its inlet, the trigger
object sends the message out its right outlet, and then a message out its left outlet. These messages are sent to the jit.gl.render
All OpenGL graphics in Jitter are drawn with the aid of jit.gl.render
objects. Each jit.gl.render
object must refer to a named destination
for drawing. You can specify this destination using an initial argument to jit.gl.render
. So in this case, jit.gl.render
creates a jit.gl.render
object that will draw to the destination window that we have named .
It’s important to note that jit.gl.render
object—only its destination.
is not the name of the
We refer to this combination of a jit.gl.render
object and a named destination as a drawing context
. A drawing context is required for OpenGL rendering. The objects on the left side of this patch are sufficient to build a valid drawing context, and so when you click on the toggle, the message appears in the Max window. This tells you that the context is being created.
object and a named destination create a drawing context
• Click on the message
object is needed in this patch because, unlike most previous tutorial patches, there are no jit.matrix
objects present. In complex patches, the drawing or matrix calculations being repeatedly triggered by a metro
object may not complete before the next is scheduled to arrive. In this example, this situation would occur if the text took more than 40 milliseconds to render. Normally, the Max scheduler would place this on its queue—a list of pending messages. Max is not normally allowed to drop messages from the queue. So in this patch, if each generated a sequence of events that take longer than 40 milliseconds, and no dropping of messages was allowed, the queue would eventually overflow
, or run out of space to store additional pending messages. Then the scheduler would stop, and so would your show! This is probably not what you had in mind. The qmetro
object (which is really just a combination of a metro
object and the jit.qball
object—see Tutorial 16
) helps you avoid this situation by dropping any messages that are still pending during a calculation. If a is scheduled to occur while the rest of the patch is rendering, it will be placed in a queue. If that still hasn't been passed to the rest of the patch by the time the next occurs, the first will be usurped
by the second, which will be placed next in the queue. And so on.
Let’s say the output of a metro
object set to output a bang every 10 milliseconds is sent to a jit.qt.movie
object, followed by some effects that take 100 milliseconds per frame to draw. So the jit.qt.movie
object will receive 10 messages during the time the effects are being calculated. The jit.qt.movie
object knows in this case that the processing is not yet complete, and instead of sending out ten messages next time it has a chance, it drops all but one. While the jit.qt.movie
objects have this capability built in, the jit.gl.render
object does not. This is because the jit.gl.render
object will often need matching groups of messages in order to draw a frame properly. In this example, the message is needed to clear the screen, and the message draws the text. If an message was dropped to avoid overflowing the queue, multiple messages might be processed in a row, and multiple copies of the text would be drawn at once, which is not what we want to do. As patches get more complex, different kinds of visual artifacts might result. So, the qmetro
object is provided to let the designer of the patch decide what messages to drop from the queue. In this example, as in most cases, simply substituting qmetro
objects for metro
objects insures that the drawing will always look correct, and the queue will never overflow.
All Jitter OpenGL objects (which all begin with "jit.gl") share a common set of attributes that allow them to be positioned in 3D space, colored, and otherwise modified—the GL group.
Drawing 3D graphics can be a fairly complex task. The ob3d group simplifies this by insuring that the messages you learn to draw one 3D object will work with all of them, whenever possible. These common attributes are fully documented in the GL group
section of the Jitter Object Reference
. To introduce the 3D group here, we will demonstrate the position, rotation, scale and axes attributes by manipulating the jit.gl.text3d
We can add a set of spatial axes to the jit.gl.text3d
object to make our spatial manipulations easier to see and understand—it's both easier to see how the text object is oriented, and also to see additional information about exactly where the object’s origin is.
• Click on the toggle
connected to the message
box reading in order to see the 3d object’s axes.
The 3D text at the origin
The x axis, drawn in in red, points to the right. Zero is at the center of the screen, and increasing x values move in the direction of the right of the screen. The y axis, drawn in green, points upwards, and the z axis, drawn in blue, points out of the screen towards you (since it is pointed directly toward you, you will only see a small blue dot). These axes represent the object’s local coordinate system as it moves through the world. When a GL group object is first created, its local coordinate system is not rotated, translated, or scaled—it has the same coordinate system as the rest of the 3D world, by default
The text “Hello, Jitter!” is displayed in the jit.window
object's display area, but it starts at the center of the screen, so the final part is cut off. Let’s move the text to the left.
• Set the number
box labeled x
in the Common 3D attributes
section of the patch to the value .
The Number box sends a floating-point value to the pak
object, which sends the message followed by three numbers to the jit.gl.text3d
object. As you change the value in the number box, you can see the text slide to the left until all of it is visible on the screen.
Changing the position attribute
We have just changed the position attribute of the jit.gl.text3d
object. The message can be followed by three number arguments that set the position of the object in three dimensions. If fewer than three numbers follow the position message, the axes are filled in the order [x, y, z], and the position of the object on the unspecified axes is set to 0. For example, sending the message . will set the position of a GL group object to the location [5, 0, 0].
The operation of changing an object’s position is called translation.
Now, let’s rotate the text.
• Set the number
boxes labeled x
directly above the pak
object in the Common 3D attributes
section of the patch to the value . This sets the axis of rotation.
• Drag the number box labeled
to the value . You will see the text rotate around the axis into the position shown in this screenshot.
The 3D text after translation and rotation
Sending the message
followed by from one to four numbers sets the rotation attribute of an GL group object. The first number is an amount of rotation in degrees, counterclockwise around the object’s axis of rotation. The other three numbers specify this axis of rotation as an [x, y, z] vector. As with the attribute, some values following the rotation attribute can be dropped and default values will be understood. If the rotation message is followed by only one number, that number is understood to mean the angle in degrees, and the axis of rotation is [0, 0, 1]. This rotates the object around the z axis, or in other words, in the x-y plane of the screen. If two or more numbers accompany the rotation message, the first one always specifies the rotation angle, and following ones specify the vector of rotation in the order in which they appear.
• Set the number
box labeled x
directly above the pak
object to . This scales the 3D text by half along its local x
The 3D text after translation, rotation and scaling
Note that the red axis scales along with the object. The dots along the line are now twice as close together as they were before the scale operation. The axes are always drawn in the GL group’s local coordinate system, which in this case has been translated, rotated, and scaled with respect to the world coordinate system in the jit.gl.render
It's important to consider the order of operations when performing geometry transforms. You can set the rotate, position and scale attributes of an object independently in any order you wish. But each time it is drawn, the object is transformed in the following order:
Keeping this order is essential so that the attributes behave predictably. If rotation occurred before scaling, for example, a
message would scale the object not just in its x coordinate, but in some combination of x, y and z depending on the rotation of the object.
The following example shows the difference that performing operations in different orders makes.
The order of operations makes all the difference
Creating a draw context is the first step to using OpenGL graphics in Jitter. A draw context consists of a named destination, such as a window, and a jit.gl.render
object drawing to that destination.
A variety of Jitter objects exist which draw OpenGL graphics in cooperation with jit.gl.render
; their names all start with “jit.gl.” The jit.gl.text3d
object is one example. All the Jitter OpenGL objects share a common set of attributes for moving them in 3D space. This group of objects is referred to as the GL group