This is a continuation of my Linear Algebra series in which I break down how to generate some Islamic Art inspired patterns using Matrices and Vectors. In the previous post I showed how these patterns can be generated easily in Python using Numpy and Matplotlib. I created an initial displacement vector which was then rotated to trace out simple primitives. These were duplicated and transformed in various ways to create a complex tiling pattern.
In this post, I will implement a similar pattern generator in Houdini's VEX. I assume the reader has working knowledge of Houdini and using vex code in wrangles. If you haven't used Houdini before, I highly recommend it as a platform for prototyping computer graphics algorithms. Side FX have an amazing development team, a great online user community and lots and lots of fantastic learning material. Here are a few links to get you going:
To the Houdini initiate/guru, the code below may scream over-complication, so I have also included a more production friendly implementation using vanilla sop nodes. The vex implementation is designed more to demonstrate the underlying maths and also show some useful matrix and array operations in vex. These operations will be useful to us in future posts.
All of the code and an example houdini hipfile can be found in the Learning Machine Learning github repo here:
To install, we need to save the file al_jabr.h into the following directory (you'll need to replace the username and Houdini version):
Now in an attribute wrangle set to detail mode (evaluate once), you can use the following two lines to create the geometric pattern:
We'll start off with the basic primitive shape function. Given a number of sides, a scale parameter and a position vector, this function returns an array of point position vectors. These points trace out the vertex positions of our basic primitive shape.
Please note: we are using 3 dimensional vectors for the positions as Houdini internally promotes them to 4 dimensional Homogeneous Coordinates. This allows the use of Affine Transformation Matrices which can represent composite Scales, Rotations, Translations, Shears and Projections all within a single matrix form.
This function demonstrates some key ideas:
1 - Using the maketransform function to create a 4x4 transformation matrix
2 - the snippet
append(pts, startP*R) shows how to add elements to an array by using iteration.
The next function will take an array of point positions and add vertices and edges to draw a shape. It uses the addpoint, addvertex, and addprim functions which are all used to create procedural geometry the smallest components. A shape_id integer parameter is included so that we can stamp each shape we draw with a unique id. This will allow us to apply unique operations to each shape later on in this tutorial
This function demonstrates some key ideas:
1 - Using
addvertex - these are building blocks to create more complex geometry in Houdini
addattrib(geoself(), "prim", "shape_id", shape_id) - this is an example of how to set attributes as you create geometry
geoself() - this is a shortcut function to return a pointer to the current geometry
We can use both functions to generate a single pentagon:
The following two functions will be used to produce more complex arrays of primitive shapes.
aj_transform_pts is a helper function to apply a transformation matrix to an array of points.
aj_add_edges is an extension of
aj_add_prim_edges to support more complex structures.
Putting it all together
The previous functions should give us the ability to create many varied geometric patterns. Much fun can be had playing around with different base primitives and applying differnt transformations and symmetries. I opted for 5 sided shapes as they seemed to give some very interesting patterns. The following final functions make up the algorithm that i used to create the following image:
These functions demonstrate the following ideas:
1 - the
scale functions transform the given matrix (in my case the identity)
2 - in Houdini, when a pointer to an existing object is passed into a function as an argument, this is called a variadic argument
3 - the snippet
append(pts, rot_pts) shows how to concatenate two arrays without using iteration
Before we end this post, i will briefly explain the compiler directives that are present at the beginning and end of al_jabr.h
These directives prevent the header file being loaded twice which is standard practice in C based languages. More info can be found here. For some reason that is beyond my wrangle understanding, these are essential for use when importing externel vex libraries into wrangles. Info can be found in the following forum post
I hope you enjoyed this post, and I look forward to seeing any work that you make using the code (please comment below)