A common use case for Shape Grammar in Unreal Engine's Procedural Content Generation Framework is building systems. In this example, you will create a fence generator that spawns several static meshes along a spline using grammar and changes the meshes when the spline control points are altered.
This sample uses the Privacy Fence Pack (with damaged sections) pack available for free on Fab. However, this example could be made using any static meshes of your choice.
Prerequisites
This how to guide uses terms and concepts discussed in the following documentation:
Project Setup
Create a new Project in Unreal Engine.
Create a new Level using the Basic level template. Save your Level.
Open Edit > Plugins and confirm the following plugins are active:
Procedural Content Generation Framework (PCG)
Procedural Content Generation Framework (PCG) Geometry Script Interop
Create the Spline
The PCG graph connects to a PCG component and a spline which are contained with a new blueprint class. Create the blueprint class by following the steps below:
Create a new blueprint class by right clicking in the Content Drawer or Content Browser and selecting Blueprint Class.
Name your new blueprint class FenceSpline.
In the Components tab, add a utility Spline and a PCG component.
Save your blueprint class.
PCG Graph Asset
The PCG Graph is the foundation of the fence generator and contains the instructions that are used to generate the fence sections along the spline. Create a new PCG graph asset by following the steps below:
Right click in the Content Drawer or Content Browser, navigate to PCG, and select PCG Graph.
Name the new asset PCG_FenceGen and press Enter.
Double-click PCG_FenceGen to open the PCG Graph Editor.
Create the PCG Grammar
The grammar is stored in a graph parameter as a string. Storing the value in a parameter makes it possible to use Parameter Overrides to customize each instance of the fence generator in the level. The Grammar attribute is then added to the spline data and passed to a Subdivide Spline node to assigned points along the spline.
In the PCG Graph Editor window, add a Get Spline Data node to the graph.
Open the Graph Settings by clicking the button at the top of the screen and create a new Parameter. Name the new parameter Grammar and change its type to String.
Set the initial value of Grammar to
A*. This will tell the graph to place an initial static mesh and then fill the rest of the spline in with static meshes as long as there is room.Drag from the output of Get Spline Data and create an Add Attribute node. In the Details panel, change the Output Target to
Grammar.Create a Get node for the Grammar parameter and connect it to the Attributes input on Add Attribute.
Click the checkbox for Accept Incomplete Subdivision.
Click the checkbox for Grammar as Attribute and set Grammar Attribute to
Grammar.
Assign Meshes to the Grammar
Each symbol in the grammar needs to be assigned a static mesh to spawn. This is done by using two parameters: Module Info and Mesh Info. Module Info contains an array of symbols. Mesh Info contains an array of static meshes. This information is passed to the Subdivide Spline node later as an attribute set.
Select the Subdivide Spline node and click the checkbox for Module Info as Input. This adds an input for an attribute that can be used to assign module information to your grammar symbols.
Create a new parameter in the Graph Settings and name it Module Info. Change the type to PCG Subdivision Submodule and click the dropdown menu next to the type and select Array. This will hold our symbol information.
Click the + button to add a new array element and click the arrow next to Index [0] to open the entry.
Set the value of Symbol to
Aand click the checkbox next to the Scalable option.Create a new parameter in the Graph Settings and name it Mesh Info. Change the type to Static Mesh and click the dropdown menu next to the type and select Array. This will hold our static mesh information.
Click the + button to add a new array element to Mesh Info.
Open the dropdown menu next to Index [0] and select the Fence_17_DE static mesh.
Create the Extract Info Subgraph
The subdivision process assigns each module a size and places a pivot point in the middle of the bounds. This creates a problem if the mesh changes later or does not have its pivot in the middle of the mesh. This subgraph extracts the size information directly from the selected mesh’s bounds and adjusts its pivot point to be at the center.
Setup the Input Node
In the Content Drawer or Content Browser, create a new PCG Graph and name it PCG_ExtractInfo.
Click on the Input node and open the Pins option in the Details panel. Open Index [0] and change the Label to
Mesh Info.Change the Allowed Types option to Point or Param.
Change the Pin Status option to Normal.
Set the Tooltip to
List of meshes to extract info from.
Extract the Mesh Bounds
Open the Graph Settings and create a new parameter. Name it Mesh Attribute Name and set the type to Name. Set the initial value to
Mesh.Drag from the output of the Input node and create an Attribute Rename node.
In the Details panel, set the New Attribute Name to
Mesh.Create a Get Mesh Attribute Name node and connect it to the Attribute to Rename input on the Attribute Rename node.
Drag from the Attribute Rename node and create a new Bounds From Mesh node.
Click the new node and set the Mesh Attribute value to
Mesh.Drag from the output of Attribute Rename and connect it to the Attribute input on the Bounds From Mesh node. The graph will automatically create a filter to create the appropriate input.
Hold the ALT key and click the output of the new filter node to break its connection.
Drag off the disconnected filter node and create an Attribute Set To Point node. Connect the output of that node to the input on Bounds From Mesh. Doing this gives the graph the ability to support both point and attribute set data types.
Click the Bounds From Mesh node and set the value of the Mesh Attribute option to
Mesh.
Adjust the Pivot Point
The pivot point on the static mesh needs to be adjusted to display correctly on the spline, drag from Bounds From Mesh and create a Multiply node.
Click on the new node and set the value of Input Source 1 to
$Extents.XThis will extract the X extents from the bounds data.Drag off from the In B input and create a Create Attribute node. Change the Double Value to
2.0.Click back on the Multiply node and change the Output Target value to
Size. This will output the full X value multiplied by two and store it in an attribute called Size.Drag off from the Multiply node and create a Copy Attributes node. Drag off the Multiply output again and connect it to the Source input on the new node. This node extracts the Z extents from the bounds data and saves it to an attribute to help with future scaling, if needed.
Click on Copy Attributes and set the Input Source to
$Extents.Z.Set the Output Target to
ExtentsZ.Drag from the output on Copy Attributes and create another Multiply node. This node will help move the pivot of the mesh to the center.
Drag off from the In B input and create a Create Attribute node. Change the Double Value to
-1.0.Click back to the Multiply node. In the Details panel, set the value of Input Source 1 to
$LocalCenter.Set the value of Output Target to
PivotOffset.
Setup the Output Node
Click on the Output node and position it at the end of the graph.
Open the Pins option in the Details panel. Open Index [0] and change the Allowed Types to Attribute Set.
Change the Pin Status option to Normal.
Drag from the output on the Multiply node and create a new Point to Attribute Set node.
Connect the output of the new node to the Out pin on the Output node.
Save the completed graph.
Return to the PCG_FenceGen graph editor window. Drag and drop your PCG_ExtractInfo graph asset from the Content Drawer or Content Browser into the viewport and select Create PCG_ExtractInfo Subgraph Node.
Apply the Module and Mesh Information
Back in the PCG_FenceGen graph, create an Add Attribute node and position it near the Subdivide Spline node.
Create a Get Module Info node and connect it to the In on Add Attribute.
Create a Get Mesh Info node and connect it to the Attributes input on Add Attribute.
Connect the Out from Add Attribute to the Mesh Info input on your PCG_ExtractInfo subgraph node.
Connect the output from the subgraph node to the Modules Info input on the Subdivide Spline node.
Drag from the output of the Subdivide Spline node and create a Match and Set Attributes node. Connect the output of the subgraph node to its Match Data input. This node takes in the point data and grammar from the Subdivide Spline and matches it with the Module Info and Mesh Info from those parameters.
Click on the Match and Set Attributes node and set the following options:
Click the checkbox next to Match Attributes.
Set the value of the Input Attribute and the Match Attribute to
Symbol.
Apply the Pivot Offset Transform
Drag from the output of Match and Set Attribute to create a Multiply node.This node scales the pivot of each mesh using data from the PCG_ExtractInfo subgraph.
Drag from the output of Match and Set Attribute and connect it to the In B input on the Multiply node.
Click on the Multiply node. Set the Input Source 1 value to
PivotOffsetand the Input Source 2 value to$Scale.Drag from the Multiply and create a Vector: Transform Direction node. This node will rotate the pivot to match the points on the spline.
Drag from the output of Multiply and connect it to the Transform input on the Vector: Transform Direction node.
Click on the new node and set the Operation to Transform Direction.
Set the Input Source 1 value to
PivotOffsetand the Input Source 2 value to$Transform.Drag from Vector: Transform Direction and create a new Add node. This node adds the final pivot offset to the position of the pivot on the mesh.
Drag from the output of Vector: Transform Direction and connect it to the In B input on the Add node.
Set the Input Source 1 value to
$Positionand the Input Source 2 value toPivotOffset.
Spawn The Static Meshes
Drag from the output of the Add node and create a new Static Mesh Spawner. This node spawns the static meshes along the spline.
In the Details panel, set the Mesh Selector Type to PCGMeshSelectorByAttribute.
Set the Attribute Name value to
Mesh.Save the graph.
Click the FenceSpline actor in the level. In the Details panel, select the PCG component and use the dropdown menu to set the Graph option to PCG_FenceGen.
Result
You should see a line of fence static meshes spawning along the length of the spline.
You can add additional variety to the static meshes by adding symbols to your grammar, defining them in your Modules Info, and assigning them static meshes in your Meshes Info. You can do this in the graph itself or on a per-instance basis using Parameter Overrides.
In the example below, the fence line has the following extra features:
Posts using the symbol
P.A gate using the symbol
G.Large broken sections using the symbol
BL.Small broken sections using the symbol
BS.
The grammar has been updated to {[A,P]:2,[BL,P]:1,[BS,P]:1}*,[G,P], {[A,P]:2,[BL,P]:1,[BS,P]:1}*.