Planet Deformation in Jettomero
Published 2 years ago
Creating Unique Procedural Meshes at Runtime
Hi, if you haven't yet heard of Jettomero then welcome! Jettomero is a game about a giant indestructible but clumsy robot trying to save the universe. It's set in a procedurally generated world where every planet you visit is never the same. Here's a shot from the game.
I recently completely redesigned my planet deformation system. Previously I was generating height maps by sampling perlin noise, but I found this wasn't an ideal method for a spherical object, especially when it came to dealing with seams on my UVs.
After setting up a system to create craters in a planet's surface I suddenly realized that I could apply this technique to all my procedural planet sculpting. Perhaps this still isn't the best method but it has allowed me to add a greater degree of control and variety so I'll be sticking with this for now. Hopefully you find it interesting and inspiring.
Here's a quick look at what the deformation looks like if I stretch it out over several frames.
The basic concept of this technique is:
1. I spawn a number of capsule colliders on the surface of the planet
2. I assign a modifier 'type' to each one which decides how it will affect the surface
3. Based on the modifier type, I find all surface vertices inside the collider's bounds and adjust their position
So far I have 3 different planet types and 3 different terrain types, which will likely expand at least slightly in the near future. Whenever I spawn a new planet a random planet type is assigned - in this example let's say it is an 'oceanic' planet. This will affect the chance of each modifier type of being spawned. Here's an excerpt from the code:
So you can see that an Oceanic planet is most likely to spawn Water terrain type modifiers. My other two current types - Average and Mountainous have their thresholds modified accordingly. When I spawn each modifier I also randomize the scale and the capsule collider's height to help get a nicer mix of terrain adjustments.
Now for the actual mesh modification. First, I find out which vertices are shared - which I didn't realize at first is essential for keeping the edges together. I create a custom class to track these shared vertices.
Next I iterate over all vertices in the mesh and assign them all to a SharedVertices in a list.
Now that I have these vertices sorted I can safely adjust them all as a group. So next I iterate through each of the spawned deformer colliders and modifying those vertices. I'll post the code first and then try to break it down a little.
The first important step to note is that I use transform.TransformPoint() to convert all the vertices into world space. This let's me adjust them relative to their planet's location, as well as check against the collider bounds which are also in world space.
Now for each shared vertices I check if it is contained inside the current collider deformer. I set a modifier value based on the TerrainType of that collider - so a water type will set the modifier to -0.25. The final vertices repositioning line looks like this:
vertices[i] = vertices[i] - dirFromCenter * (g.transform.localScale.x - distFromCenter)/2.0f * modifier;
Using the dirFromCenter Vector3 is essentially the same thing as the up/down direction of that point, which can't be a global value since each point on the sphericial planet has it's own concept of up. You'll also notice that I modify the value based on distFromCenter, which is how far the vertices are from the center of the defomer collider. This let's me get a gradual rolloff of the deformer's effect, otherwise all the vertices will be pushed down at the same amount creating jagged cliffs (which I may actually want to include occasionally later on).
Now one last detail in here is that after modifying each set of shared vertices, I alter the scale of the collider deformer slightly, this means that some of the vertices originally contained in the collider will no longer be and vice verse. The purpose of continually modifying the scale of the collider is so that the final shape of the deformation isn't too smooth. Otherwise I'd end up with perfect circles cut out of the ground which doesn't look nearly as natural.
I plan on continuing to tune the planet deformations and will likely add more varieties of both planet types and terrain types but I'm relatively satisfied with this method. If you have any questions or want to continue following progress on Jettomero feel free to @ me on twitter @GhostTimeGames.
Gabriel Koenig
Creator - Owner