Gen 3: The Fine Art of Surfacing

In the first and second tutorials tutorials in our Gen series, we’ve taken a look at the gen~ object for processing audio data and the jit.pix object (and its cousin jit.gl.pix) for processing 2d, 4-plane image data. This time out, we’re going to have a look at the jit.gen object – while it’s just like the jit.pix and jit.gl.pix objects in that all three objects process jitter matrices, the jit.gen object is the generic Gen matrix processing object – it can handle matrices of any type, dimension, and planecount.

Expressionism

Before the arrival of the Jitter Gen objects, one of the best techniques for processing matrix data in interesting and complex procedural ways was to use the jit.expr object. Andrew Benson’s tutorial on working with expressions using the jit.expr object did a great job of demystifying normalized numbers, and our last tutorial on image processing using jit.pix made use of those insights to help explain how Jitter gen objects work with matrix data.

Working with jit.gen uses those same basic skills, but we’re going to look at how a little familiarity with the Jitter family of gen objects can make working with expressions that can seem bewildering in jit.expr a lot easier. We’re going to generate a data surface – a mesh whose contours are described by a mathematical expression. This is a quick way to grasp just how much the arrival of the Jitter family of gen objects has made your life a more pleasant place.

To start, let’s take a look at the jit.expr object in action, and review how we use it to represent matrix data (both in jit.expr and in the jit.gen world, as well. The patch contains all the logic we’ll need to start – it provides the standard set of objects we use when generating and rendering matrix data in Jitter, along with a jit.expr object that we’ll use to generate our data surfaces.


View the full-sized screen shot.

The patch contains a number of jit.gl.mesh attributes that you’ll see in all of our example patches (after you’ve generated your data surface, you might want to take a few minutes to investigate how they alter the look of the rendered matrix if you’re not already familiar with them). We’ll create our mesh using a 3-plane matrix of 32-bit floating point data whose dimensions are 100 x 100. Each of the three planes represent a dimension of our 3d data, which we’ll send to the jit.gl.mesh object:

  • x = width
  • y = depth
  • z = height/displacement

We’ll use a jit.expr object to create our 3d plane by using expr messages to fill the matrix with data values that describe our plane. As we go along, we’ll also use variations of those messages to create more interesting variations on the plane.

Let’s start with something simple – a plane whose coordinates all lie within the range -1.0 to 1.0. As you may know from Andrew Benson’s tutorial (or the previous jit.pix gen tutorial), we can do this by specifying signed normalized (snorm) values to specify the coordinate range for our data surface. Sending the message expr snorm[0] snorm[1] 0. to the jit.expr object does just that -the number in the square bracket indicates which plane we’re specifying – since the plane is completely flat, all of the values for the z plane can be set to zero by including a value of 0. rather than snorm.

While that works well, it’s not very interesting. We can create variations in our data surface by replacing the zero with a mathematical expression that will describe the z-plane values for every single point on our data surface. The expression sin(snorm[0]*PI) does just that. for every x value across the plane, the z offset is calculated by multiplying the x value by 3.14159 and then calculating the sine of that value (which will always remain in the range -1. to 1.) The result is a single cycle of a sine wave that ripples across the x dimension from left to right.

The expression sin(snorm[1]*PI) has a similar result, but the sine wave propogates along the y axis (from top to bottom).

Suppose we wanted to have the sine function propagate along both axes at the same time. How would we go about doing that? To combine the sine waves together, all we have to do is to combine the two expressions we have, but add the results together and take their average. The expression expr snorm[0] snorm[1] (sin(snorm[0]*PI)+sin(snorm[1]*PI))/2 will do that.

Moving Waves

While this data surface is certainly lovely, it’s still a litle static. Don’t worry – as I learned from Andrew Benson, the jit.expr object allows you to work with variables in our expressions. In the jit.gen_2 patch, we’ll introduce variables and use them to do two things:

  • We’ll let you set the number of iterations of the sine function across the x and y axes.
  • We’ll add a scaling variable to change the amount of vertical offset for our plane.

You can specify input variables in a jit.expr expression by typing in[N] , where N is the number of the inlet associated with your variable. The number of inlets that the jit.expr object has will vary according to the number of variables we specify. They appear to the right of the jit.expr object’s left (matrix) inlet, and and numbered starting with 1.


View the full-sized screen shot.

Gen 3: The Fine Art of Surfacing

Mar 13, 2013 at 3:06pm

Thank you for these Gen tutorials! They’ve been very helpful since I find that the documentation for Gen is still a bit obscure. I’m looking forward to the next one!

#260559

You must be logged in to reply to this topic.