Project 2 - Random Terrain Generation

ARCH 655 - Project 2

Project Brief

In this project, the goal was to create a random terrain generation tool. This tool could be utilized to create natural looking terrain and surfaces such as mountains, hills, cliff faces, and other topographical surfaces. These generated surfaces could then be used to model buildings and landscaping around. 

Below we see an example outcome from the generator.


This example is only the beginning of what is possible with this tool.

Before I show more of what this tool can produce, I will give a brief tour of how this simple tool works.

Project Scripting

This project utilizes a mixture of Grasshopper, Python, and Kangaroo to achieve the various outcomes. 

It starts with a Grasshopper Python node with a few base inputs to lay the groundwork for the rest of the script. 


There are five main variables: GrowthLength, PeakFactor, ExtentX, ExtentY, and Focus.

Taking a look at the Python script itself we can see how each of those variables are used. 

The GrowthLength variable defines how many cycles the script will undergo in generating the resulting ridgelines.

The PeakFactor defines the initial height limit.

The ExtentX and ExtentY variables define the maximum positive and negative range available for point generation. 

Lastly, the Focus variable defines how centralized the generation is. 

Looking at the first part of the script, we see how points are initially added.

The "placePt" definition, utilizes four of the five input variables. The x and y coordinates of the point are defined by a Gaussian bell curve distribution. This Gaussian distribution allows for us to greater control how centralized the peak of a mountainous terrain would be. The remaining z coordinate uses a uniform distribution so that there is a gradual progression to the base of the mountain.

The cycle generation of the ridgelines contains the information as to how the points are finally organized.

First, the script will generate a point, somewhere within the defined X, Y, and Z extents (defined by ExtentX, ExtentY, and PeakFactor). This point will then find the closest point from the existing tree of points and draw a vector between them. Now that a direction has been defined, the magnitude of that vector needs to be adjusted, for simplicity, it is converted into a unit vector. The generated point will then be moved by the difference between the original vector and the unit vector, resulting in the unit vector. Once this point is finished being generated, it is added to the existing list and the next point can begin this cycle once more until it has exhausted the GrowthLength variable. 

Now we have to prepare these points for Kangaroo and application to a mesh. 

To do so, we take the list of output points from the python script, cull the Null origin point, and deconstruct each of the points. For Kangaroo we need each force point to line up with the vertices of the impacted mesh. Rather than making the mesh line up with this random assortment of points, we will line the points up with a uniform grid. The x and y components of each point are rounded to the nearest whole number so that from the top view, they will all fall into a uniform grid. They are then reconstructed, discarding the z component in the reconstruction as it will be used in a different way. We then create a bounding rectangle. This will ensure that the mesh is always big enough for the points being used to generate the surface. 

The bounding box is then turned into a boundary surface to be used as the mesh base and the x and y dimensions of the bounding box are then used as the U and V counts for the mesh, again to ensure that the points will line up with the mesh vertices. 

The following portion of the script are the forces that then go on to create the final mesh shape.

There are four different forces that act on the mesh:

- There is the mesh itself that has a tensile strength to resist the other forces acting on it.

- There is a gravity force that acts on each vertex of the mesh.

- There are the upward, force vectors created from the python generator.

- Then there is an overall random jitter applied to all of the clothed vertices of the mesh. 

The tensile and gravity forces are rather self explanatory in nature, so I will not go further into their purpose. The two remaining forces do require some explanation on their purpose or composition. 

Starting with the force vectors based on the points from the python generation script. The Unary Force node takes in two inputs: The reconstructed rounded points, and a force vector. Since the reconstructed points has already been explained, all that is left is explain how I use the leftover Z-component from earlier the earlier deconstruction. This z-component is multiplied by a height scale in the z direction to create the different forces. Since each point had a different z-component, each force vector has a different vector corresponding to the initial point's z-component. 

The overall random jitter is the last force needing explanation. Without the jitter, the mesh generated was smoothed and unrealistic. Therefore, applying a random force amount to each clothed vertex of the mesh in the positive or negative directions, gave the mesh a more rippled, natural surface texture. This is also multiplied by a scale to generated varying levels of roughness.

Kangaroo now has all of the components it needs to apply a physics calculation to it. With the mesh, anchor points (naked mesh edge points), and forces, all that is left is to fix a minor issue and give the mesh a bit of color.

Earlier it was mentioned that without the random jitter, the mesh became too smooth, however since the vast contrast in force vectors is so great, the mesh is being pulled quite tight, resulting in heavy triangulation. This is solved by applying a full strength mesh smoothing node. This is enough to ease the drastic mesh triangulation, but not enough to smooth out all of the detail we added with the jitter. 

Lastly we move to coloring our mesh. We once again deconstruct our mesh to get all of our vertices and deconstruct the vertices to get their coordinates. Utilizing only the z-component of the vertices, and sorting the their values from low to high, we are able to provide the gradient node with a range in which to apply the color scale to. In the case above, the lower points receive the darker grey to the left of the gradient slider, and the higher points receive the lighter grey  to the right of the gradient slider. This is then applied to the mesh and input into a material preview, mixed with a semi-gloss paint layer to create the final output. 

With that, this concludes what went into creating this tool. All of the necessary information needed to recreate this for your own use can be found throughout the various images of this post, so feel free to do so if you feel it would be useful for a project of yours. 

To round out this project, I would like to show a few outcomes that were made possible through the use of this tool. Followed by a short video overview of the script. 

Mountains

Rough Cut Stone Face

Ocean Waves

Island

Video Overview

https://youtu.be/L2VxBXVQ204

Comments

Popular posts from this blog

Project 1 - Mercedes-Benz Atlanta Falcons Stadium