Environment


Terrain

My general workflow when creating terrain to produce heightmaps using Quadspinner Gaea, add additional procedural features such as rivers, paths, and clouds in Houdini, then set up detailed landscape materials in Unreal Engine.

I am particularly interested in developing tools and automation to help environment artists create outdoor scenes quickly and efficiently, as well as deep diving on ways to improve engine performance.

See the linked blog posts below for more detailed technical breakdowns of various terrain projects.

Blog: Blending Landscape Materials Blog: Texture Variation Techniques in Unreal Blog: Fix Heightmap Blacklevels with Python

Editor Tools


Hex Engine

I developed a custom editor tool for building custom hex map overlays on top of Unreal Engine landscapes. The tool implements common hex math equations in both C++ (with exposed blueprints) and HLSL. The overlay can be activated as a "preview mode" post process material that projects on top of everything in the scene, with a couple masking options provided: height based masking, which reads landscape height data from a render target and masks out pixels with a height value too far away from the landscape, and custom depth buffer masking which masks out objects that have been written into the custom depth buffer.

The tool also provides a selection mode where users can select hexes directly in the editor viewport. This mode works by peforming line traces against the landscape based on the position of the cursor and then writing selection data into a custom render target where each pixel contains packed hex selection data for each hex in the grid.

GitHub - Hex Engine

Automation Graph

I built a custom graph editor for Unreal Engine that allows you to automate the process of cooking multiple Houdini assets at once. The graph system also supports triggering non-houdini specific actions, such as calling UE console commands.

The graph editor is written entirely in C++ and packaged as an Unreal Engine uplugin. Visit the "Houdini Build Sequence Graph" github link below to see the code and additional documentation.

I later generalized the Houdini graph code into a framework for Unreal Engine automation. This framework does not have any dependency on Houdini Engine and adds additional functionality like trigger nodes that can cause a graph to execute on editor startup, and a node for executing unit tests.

The graph editor is written entirely in C++ and packaged as an Unreal Engine uplugin. Visit the "Automation Graph" github link below to see the code and additional documentation.

Overview Video - Houdini Build Sequence Graph GitHub - Houdini Build Sequence Graph GitHub - Automation Graph

Gameplay Systems


Mantle ECS

Back in 2023, I built a Entity Component System (ECS) for Unreal Engine because I wanted to better understand how the Mass Entity ECS system provided by Epic works under the hood. This ECS takes much inspiration from the Mass Entity, but was built from scratch with a more simplified API and a focus on exploring how ECS systems can be integrated with other gameplay systems like player perception or ability systems.

Something still bugged me: I was interested in capturing some of the organizational benefits of ECS archetecture, but felt that this system still had too much bespoke memory management and complex internal code. More recently, I've decided to do a full re-write with a focus on using the standard Unreal framework as much as possible.

To see the code and additional documation, see the github links below.

GitHub - Mantle ECS GitHub - Mantle2

Procedural


PCG: Extract Collision Boxes

Here is a PCG tool I created for scattering mushrooms across a surface. Points are generated on the target mesh and then culled using a number of different strategies:

  • Placement of the point relative to the height of target mesh
  • How much the direction a point is facing deviates from the up vector
  • Random pruning
  • Overlap reduction
  • Intersection of mushroom caps with target mesh (more on this below)

One interesting problem I ran into was that occasionally the mushrooms would clip into the tree stump mesh. I needed a way to detect intersections of the mushroom caps with the tree stump, while ignoring the mushroom stalks (these are okay to intersect). In this case, doing a simple bounding box detection is not enough.

The solution I came up with was to add special collision boxes to the mushroom meshes representing the mushroom caps. I then created a new custom PCG node called ExtractCollisionBoxes that allows you to generate point data from a collision box on a mesh. You can tag the collision box with an id to grab a specific one, otherwise it will just grab the first box it finds. These extracted points can then be pruned based on if they intersect with points sampled from the target mesh. My custom node is written entirely in native C++.

GitHub - PCG Tools Blog: PCG Difference Node Explained

River Generator

I created a river generator HDA that takes an Unreal Engine landscape spline as input and then generates a river mesh based on the path of the spline and the width of each spline segment. Flowmap data for scrolling the water material along the path of the spline is computed in Houdini and stored in the vertex colors of the mesh.

One challenge I ran into was that the SideFX labs flowmap generator produces colors in UV space, which leads to artifacts at each bend in the spline. I rewrote the VEX code for computing the flowmaps to output world-space colors, and was able to get a much cleaner result.

For the river material, I created a simplified version of the water material included in the UE Water System Plugin.

One thing I would like to improve in the future is the realism of the ripple effect. With the stock UE "flowmaps" node, I'm still getting a bit of noticeable flicker as it blends between the normalmap and the time-adjusted normalmap. I'd like to explore more techniques for improving this, such as this technique from Prismatica that adds a third blend so that at any given time, one texture sample is being blended in, one is being blended out, and one is steady.

To see the code and additional documation, see the github links below.

Blog - Understanding TexCoord & Flowmaps

Fence Generator

I created this fence generator HDA that assembles prefabricated fence sections and runs a stagger computation that splits up the sections into smaller subsections based on how sloped the landscape is.

Fence pickets and posts are exported from Houdini as Instanced Static Meshes, and additionally the posts are rotated randomly for some visual breakup.

My original goal was to create a generalized fence generator that could support many different fence types. As I worked on the project, I realized that making a lightwight tool (in terms of number of configurable parameters) is feels more practical since most users of the tool are probably mostly concerned with making the "big decisions" as opposed to having dozens of small tweakable parameters.

One thing I would like to improve in the future is supporting more fine-grained control at the end of the spline. Due to the fact that this tool does not allow stretching, the post placed at the last point on the spline cannot easily be positioned exactly where you want it. In the future, I would like to find a way that both ends can be positioned exactly.

Blog - Fence Project Breakdown

Pipeline


JSON Asset Definition Library

I created a Python library for saving Houdini parameter configurations out to a JSON file. The initial motivation behind this project was due to the fact that I wanted to create a TOPnet that could generate variants of some particular geometry based on a file definition. I first tried using the built-in Houdini parameter preset feature, but had trouble accessing the preset from inside the TOPnet.

An added benefit to going the JSON route is that the file is human readable and the common data format makes it ideal for integrating into larger pipelines.

I later added support for multiparms as well. I used this multiparm functionality in a headstone generator I created to define an arbitrary number of cracks for each headstone asset definition.