Procedural Geometry - Pipes

A brief example of generating procedurally generating pipes. Used for creating a backbone in a protein visualization.

pipes1.gif

The concept of generating geometry in Unity is not complicated. You have a list of vertices, and you tell Unity how those vertices should be connected to form triangles. Additionally you can provide information about UV layout for texturing and lighting / generating smooth normals. In the end you have three lists, vertices, triangles and UVs. You assign these to a mesh component and you get a mesh out of it. One thing to note is that vertices for each triangle must be assigned clockwise.

This tells Unity that the triangle is facing outwards and you will see it's surface. If you assign them counterclockwise the triangle will be facing inwards and will be invisible. For a much more in depth and eloquent explanation, see the tutorial on mesh generation from Catlike Coding.

For my purposes I need to generate pipes, to illustrate the backbone of a protein. A few things have to be done:

  1. Take a set of world space coordinates (location of amino acids) and use them as points along the pipe.

    • I already have those coordinates for my space filling model.

  2. Create a circle of vertices around each point, to define the profile of the pipe

    • I can get the x and z (or y) coordinates using the parametric equation of an ellipse, with the radius value equal on each axis.
      x = r cos t
      z = r sin t
      x and z are coordinates I'm trying to find. r is the radius, which could be different for each axis. t is my angle in radians. 360° = 2π radians, so if I divide by n (the number of sides I want), I get a step size which I can add to t, n times, to get my circle of points.

  3. Rotate these circles so they form nice corners at each turn. Three was the difficult step for me conceptually. My end solution was as follows:

pipes2.png

Given three points, A, B, and C, get the vector AB, BC, and AC. Take the average vector of AB and BC. Get the cross product of AB and AC. Average vector tells me where the circle should be facing and the cross product gives me the normal of triangle ABC. I use the cross product to define "Up" and the average vector to define the "Look" value in Quaternion.SetLookRotation(crossVector, averageVector).

Average vector (Green)

Cross product / normal (Orange)

 

This gives me a quaternion that defines the plane and start point of each circle. I was getting weird twists in my pipes, where the start point for the circle would flip. When I connected my vertices they would cross to the opposites side of the next joint, bascially 180 degress around the the next circle. To keep everything lined up, I took the absolute value of each XYZ value in the cross product vector, and made this my up direction. No more twists!

The end result is that for each point P in my backbone I use the previous point (P-1) and the next point (P+1) to calculate the orientation of the cross section at P. I could have used more cross sections to create smoother angles but as this is for VR purposes, poly counts must be kept low.

Previous
Previous

AWS .NET SDK in Unity

Next
Next

Optimizing instantiated geometry for VR