Developing Tools for Large-Scale 3D Game Environments
Jolan Huijskes discussed a suite of Blender and Unreal Engine 5 tools he built to create a fully playable game environment, envisioning a desert biome for Saros.
Introduction
Hi there! My name is Jolan Huijskes, an Environment Artist who specializes in technical solutions. I recently graduated cum laude from Breda University of Applied Sciences. You can check out my work on ArtStation.
I showcased the value of technical skills in previous projects, like when I created the peeling paint effect. I enjoy technical challenges like those, so I decided to invest more heavily into my technical side with this latest environment.
This fan art project is an exploration of how environment art tools can be used to create large-scale levels for games with maximum control for Level Artists. I focused on tool development, composition, and art direction.
In this article, I will explore how and why I developed these tools for my fan art project:
- Blender Fracture Generation (tool to be released for free soon)
- Unreal Engine Array Tool
- Unreal Engine Fracturing Tool
- Unreal Engine PCG Scattering with Artist Control
Everything in this project is made by me and is unrelated to my professional work.
Tool Philosophy
Procedural solutions are undoubtedly powerful and common in productions, but they are also a source of frustration for artists. I once used a Houdini tool in Unreal Engine that would delete your work if you clicked on the next asset!
The goal of this project was to develop tools that I would enjoy using as an environment artist. I came up with a few design principles based on my experience in other projects:
Minimize friction: If a tool feels complex or unintuitive, artists will avoid using it. That can lead to unoptimized or destructive environments.
Minimize waiting time: When a tool requires 5 minutes of waiting for the output, the artist may have forgotten which changes led to this result. This makes the tool harder to use and can lead to accepting poor outputs.
Maximize artist control: In AAA productions, every detail matters. Artists receive feedback from Designers, Leads, and Directors that can be extremely specific. If the tool lacks sufficient manual control, it will not meet their demands.
Blender Fracture Generation
To create the fracturing system I was envisioning, I first had to generate the fractured pieces of my modular kit without affecting the modularity of the meshes. This was extra challenging with this seamless architecture. Any fracture lines or edge damage on the top/bottom of a pillar would reveal where one piece ends and the next begins.
Typically, offline mesh fracturing is done in Houdini with tools like the RBD Fracture Node. Houdini is undoubtedly the most powerful and versatile solution, but it clashes with some of the principles I laid out before:
- Using Houdini means additional software. This can add friction for artists.
- Using Houdini means importing/exporting into Houdini, which means additional development time.
- Using Houdini means re-processing your meshes if any changes are made.
The solution to these issues? Create a solution directly in Blender for fast and frictionless results.
Initially, I tried the native Blender Cell Fracture, but as an outdated and complicated Python add-on, it didn't easily allow me to customize it for my purposes. For example, I saw no easy way of subdividing and adding noise to create more complex fracture lines.
Instead, I decided to use Geometry Nodes to develop my own fracturing system. Geometry Nodes are already quite powerful, and the system continues to be expanded with features (in 5.2, we got Physics, Geometry Bundles, Lists, the long-awaited Mesh Bevel node, and much more).
The starting point of my system is the same as the Fracturing system by CGMatter. This base system outputs some problematic results: It creates extremely thin pieces, it creates extremely small pieces, and it doesn't cut meshes at natural breaking points.
Through various resources and iterations, I built a more consistent and realistic algorithm. This is a simplified overview of the system (see images):
Base Fracture
Repeat X times for each mesh island:
- Create a plane along the mesh's longest axis
- Displace the plane with 3D noise
- Use a Boolean with the plane to cut the mesh island in two
Interior Detail
- Displace the interior using 3D noise
Edge Damage
For each mesh island:
- Remesh
- Inflate the new mesh with 3D noise
- Boolean the new mesh from the original mesh
The Base Fracture system is very similar to CGMatter's tutorial, but with some key improvements:
- First, by only cutting large islands results in more consistent fracture sizes
- Second, I cut the mesh along its longest axis using Matrix SVD (see image), which results in more realistic breaking points
- Other minor changes for consistency and performance
The Interior Detail is done by displacing the interiors of the fractures. The current version uses a Triplanar Projected texture, but I plan on replacing this with 3D noise for the free release.
Finally, the Edge Damage section is based on Cartesian Caramel's approach: Remesh the model, apply some noise, and boolean it from the original mesh.
Through development, I found that user-friendly debug tools were valuable. I added the option of removing or separating fractures to view the interior, and those functions proved very useful. I recommend developing debug functions for your tools!
After the Geometry Nodes effect, the meshes are prepared for export with a custom add-on I made. The final result is a fracturing tool that is applied non-destructively in Blender. It is easy to use and optimized. It doesn't require any external programs and is easily adjusted later, if needed.
The tool will soon be released for free. I am working on improving the UI/UX of the tool, removing all dependencies, and making it compatible for customization. I also have some ideas for future improvements, such as a manual single-cut option that lets the user control the exact position and angle of the cut. Follow me on Twitter/X for updates.
The following sources were instrumental in my work on this tool:
Unreal Engine Array Tool
To construct the seamless, vertical, and repetitive architecture of my fan art project, an array tool seemed obvious. The goal was to non-destructively construct repetitive architecture with extreme scales using a modular kit.
Developing this system went quickly since it's quite straightforward. Using a For Loop, you can easily place meshes in a row. With a second For Loop, this becomes two-dimensional.
This is a simplified overview of the system:
1. Add Instanced Static Mesh Component
2. For Loop ([Repeat 1] amount of times):
2.1 Add Static Mesh Instance at [Transform 1]
3. For Loop ([Repeat 2] amount of times):
3.1 For each existing instance:
3.1.1 Add Static Mesh Instance at [Transform 2]
This tool is simple but pleasant to use due to its intuitive controls. Make sure to enable "Show 3D Widget" in the Transform parameters. This will allow the manipulation of the blue gizmo in the 3D Viewport.
I created this system using Component Script in Blueprints. Fortunately, there is a lot of content on this topic. The biggest challenge was adding Randomization (random flipping of meshes), which I didn't fully solve. Perhaps someone else can improve on it!
Another major limitation of my tool is that every new BP is a new Instanced Static Mesh component. Perhaps you can improve this system by batching all Instances in the level. Look into "ISMCellTransformer" if you're using World Partition (tip from Kay Volbeda).
With those limitations in mind, I would recommend exploring Unreal Engine PCG for this tool. That will allow for greater optimization and interplay with other PCG systems.
Unreal Engine Fracturing Tool
The next step of the fracturing system is in-engine: a tool for a Level Artist to non-destructively destroy architecture. Again, there are existing solutions for this, usually Houdini HDAs in-engine. However, I intentionally pre-fractured meshes in Blender to have a responsive tool in Unreal Engine that isn't dependent on connections with other software.
I knew the general concept: Reconstruct a mesh out of smaller pieces, then delete/hide pieces based on collision with a sphere. Thinking about this concept, I knew there was one major problem to solve:
- Fractured meshes in Blender are separated
- These fractures need a centered origin for manual set dressing in-engine
- In Unreal Engine, architecture meshes must be reconstructed from fractured meshes
- Problem: How does the system know where to place a fracture? How is the location of the fracture saved, exported, and used in Blueprints?
For every fractured mesh, a location (a vector) needs to be stored. I thought of a few different options:
- Custom data in the export file: How does that work with FBX? Do I need to use GLTF for this? Sounds complex
- Saving a list of data in JSON: Very software-agnostic, interesting skill to learn, but also sounds challenging. How can Blender even export this data to JSON?
- One hidden vertex per mesh at the right location: How can that vertex location be accessed from inside Blueprints?
- The solution: Sockets
Sockets are an Unreal Engine feature. They are special Transforms stored in a Static Mesh used to attach other meshes (like a door to a doorframe, or a sword to a character's hand). I decided to utilize this feature to store my data.
If an Empty object in Blender is called SOCKET_{SocketName}, Unreal Engine will detect it as a Socket. Therefore, every fractured mesh is exported with an Empty in the correct location using a Blender add-on I wrote. That Socket position can then be accessed through Blueprints in Unreal Engine.
Working with the Construction Script in Unreal Engine, I built the logic of this tool. This is a simplified overview of the system:
1. Fracture Sphere BP casts to nearby Mesh BPs:
1.1 Delete main mesh
1.2 For each fractured mesh in the array:
1.2.1 Add fractured mesh
1.2.2 Move fractured mesh to location stored in Socket
1.2.3 Check for overlap with nearby Fracture Spheres
1.2.4 If overlapping, delete fractured mesh
Overlap is checked with the nodes "Component Overlap Actors" and "Sphere Overlap Components." The Socket location is found with the node "Find Socket".
The result is one of the most pleasant tools I've used. It's responsive, easy to use, and completely controlled by the artist. The tool is not without its downsides. Firstly, I did not integrate this with the Array Tool. If I had more time, I might've tried to combine the logic. It's definitely possible, but time-consuming.
Secondly, I did experience some minor performance issues when using many Fracture Spheres (over 150). I am unsure how to improve the performance. If you have any suggestions, please let me know!
Unreal Engine PCG Scattering with Artist Control
Scattering assets like debris and foliage is typical in most environments. PCG has recently become a popular solution for this, but it also comes with some challenges. Unlike manual placement or foliage painting, it lacks control for the artist by default. Manual control is very important in polished game environments: for composition, clear player pathing, and environmental storytelling.
Still, PCG is performant, flexible, and connects well with other Unreal Engine systems. I set myself a challenge to make a PCG system that is both procedural and controllable. The first useful element to highlight is using the "Actor Data" node with All World Actors, By Tag, and Get Single Point. This allows your PCG graph to be more level-aware. I used it to scatter rubble around broken architecture, but I'm sure you can think of your own creative applications.
I added manual control by creating an Actor Array Variable. Plugged into the "Actor Data" node, this allows you to pick actors from the level by hand. You can use this to scatter more meshes around those actors, or instead, use it to remove meshes in that area.
A "Select" node is useful to contain different behaviors in the same graph. For example, my debris should only spawn close to tagged meshes, while the grass should spawn everywhere.
Putting these ideas together, I created this procedural tool that complemented my destroyed architecture. I relied on Tags and a Picker, but you can explore other options too! Maybe it should be more driven by landscape data or Blueprint actors.
For the best Unreal Engine PCG learning, I highly recommend Adrien Logut's YouTube Channel and Procedural Minds' channel. You can also ask questions in the Unreal Source Discord server.
Conclusion
I hope this article has been insightful for you! When you're developing your tools, make sure they're responsive, easy to use, and can be controlled by the artist.
I plan on releasing my Blender Fracture Generator for free. I need to fix some dependencies, UI/UX, and find the best way to make it available. Stay tuned for updates on this!
If you have any questions, please feel free to get in touch with me!
Check out my portfolio on ArtStation.
Connect with me on LinkedIn.
Follow me on Twitter/X.