Introduction
About me
Hello, my name is Jeroen Denayer and I’m from Belgium. I am a Technical Artist currently studying a Digital Arts & Entertainment program at the Howest university of applied sciences for my Bachelor’s Degree.
Why did I choose Python in Houdini?
The game industry is all about speeding up game development. Games are becoming bigger, more qualitative. Companies are met with ever increasing pressure from tight deadlines to get new updates out for the player. And of course getting as many sales as possible. This is made possible thanks to amazing tool developers who create easy to use, highly interactive tools that update real-time in a game engine when the user changes something. This keeps the user from going back to their modelling software > changing an asset > exporting to disk and reimporting into the game engine. My personal interests are completely in line with this mindset of automating highly repetitive work while still focusing on art directability. Everything related to scripting, proceduralism and getting your assets inside of a game engine as fast as possible is a great interest of mine. That’s why I wanted to research all the steps from creating a tool to in the end having an artist use the tool inside of a game engine.
What to expect?
As a practical proof point I have created a Houdini Digital Asset (HDA) that helps in the creation of a procedural racetrack that can be integrated into Unreal Engine. Instead of updating parameters of the Houdini Asset in Unreal, I will make use of Houdini session sync and python viewer states to change parameters of the HDA in Houdini. This will allow us to make changes to the racetrack inside of Houdini and see it automatically update in Unreal as well.
Here is what I will cover:
- How to interact with objects in your viewport using your mouse and keyboard.
- How to make a super interactive UI that can be navigated using only your mouse and keyboard.
- How to store all the data of the entire racetrack in one json.
- How we can get this json into our geometry network so we can construct the racetrack mesh from it using regular Houdini nodes..
- Why I made the decision to use certain features such as Houdini session sync and python viewer states.
- How to integrate this tool into Unreal Engine
I will not cover:
- How to use this json data to create the racetrack mesh itself
Literature/prior-art study
Creating racetracks
Starting off with looking for what’s already been done in this field I found some interesting sources which helped me with my research. Let’s start off with the creation of the procedural racetrack itself. There are a couple of techniques that are commonly used to create racetracks for games.

Pre-made segments
In this approach you create pre-made segments of the track (corner segment, straight segment, etc…) and then place one segment after the other to create the track. The Trackmania games make use of this approach. The advantage is that different tracks are very consistent in their style as they consist of the same pre-made segments. The disadvantage is that you loose the ability to create very specific turns like 17.6 degrees to the left as all the segments have pre-defined standard angles like 45 or 90 degrees.

Bending pre-made segments
A second option is to create pre-made segments that have multiple edge loops along their length and then bend them along a curve inside of a game engine. This approach is often used for cables inside of games and gives you the freedom to turn in any direction. But it comes with some negatives. It is a quick and dirty way. These extra edge loops are wasted geometry on straight parts of the curve and this bending method can also cause pinching and stretching of UV’s at parts with a high curvature.
Fully procedural racetrack
Using Houdini, the company Space Ape created a fully procedural racetrack based on an input curve that defines the main shape. In this GDC talk, they explain all the benefits of using this method. It gives you full flexibility over the direction of your track, optimization of polycount on straight parts and automatically creating correct UV’s for your track. Their tool was directly implemented inside of a game engine and updates in real-time when a change is made. This is thanks to the Houdini Engine for Unreal plugin which connects both software. It allows you to change parameters inside of Unreal Engine and in the background Houdini will re-calculate the output. Space Ape created their game in Unity but everything is applicable to Unreal Engine as well.


Limitations of Unreal and Houdini Engine
The tool that Space Ape created was amazing! They could fully customize tons of parameters to change the visual look of the racetrack. However, to do this they still needed to drag around sliders in the UI. This is the normal way of working when working with Unreal and Houdini. But this doesn’t fit in with the idea of making everything as interactive as possible for the artist that will use the tool in the end. What I want is something more like how you would model in Blender. Every action is done inside of the viewport using simple mouse clicks and keyboard shortcuts. And this is something that I wanted for my own racetrack tool as well. This is when I found out about Python viewer states.
Python viewer states
Python viewer states are a way to interactively update parameter values on your tool or HDA using mouse clicks and keyboard shortcuts.
I found that some students from the Breda University of Applied Sciences (link) had already built something that was similar to what I wanted to do. I used their tutorial as a starting point for my own tool. They implemented some interactivity but I wanted to take this even a step further. I wanted to navigate the entire UI of my tool purely using python viewer states.

So using python viewer states we can now interactively work with our tool. But what is the benefit of using this approach if we can’t get our racetrack back into Unreal Engine? We can achieve this using Houdini session sync. This allows us to open a live connection between Unreal and Houdini and we can now jump back and forth between both softwares, change something in one and it will immediately update in the other and vice versa.
Conclusion
What was very clear to me, is the workflow/pipeline that I would use during my research. First create a tool inside of Houdini. Afterwards convert it into a digital asset which can be imported into Unreal engine. Then using Houdini engine and Houdini session sync we can open a live connection between the softwares and use python viewer states in Houdini to change parameters on our racetrack tool.
Some questions that occurred to me after doing my literature study and before starting on my own tool were:
- How does the tool compare when built with and without python viewer states? What are the pros and cons?
- Is using Houdini engine in combination with Houdini session sync a benefit to the game asset creation pipeline?
Workflow
Overview

Here you can see an overview of how I connected all the different parts.
- Step 1: create a standard procedural Houdini network using nodes.
- Step 2: convert this network into a tool/HDA and import it into Unreal with the Houdini Engine plugin.
- Step 3: change the position of curve points in Unreal Engine to shape the racetrack.
- Step 4: use Houdini session sync to open a live connection between Unreal and Houdini.
- Step 5: interactively work with the tool in the Houdini viewport using python viewer states.
- Step 6: the viewer state will automatically update the UI when the artist changes something in the viewport.
- Step 7: the python module will run when the artist changes a parameter value in the UI directly
- Step 8: the only reason that this UI exists is to construct a json file that will hold all the data of the entire racetrack.
- Step 9: json parameter and other parameters that will help us to construct the json.
- Step 1: the procedural network will read in this json and construct a complete racetrack from it.
Prototyping
This will be a more technical part as it is all about using Python. I will always mention all the functions that I created and explain their functionality. I will not always show the code as some of it is just Python basics. Making use of an external code editor is highly advisable but not necessary. I personally used Visual Studio Code. To interact with Houdini using python we will make use of the Houdini object model or HOM for short. This is a python library that allows you to interact with Houdini. If you don’t now how something works, or how you can get access to a certain part of Houdini. Then HOM is your best friend. Thousands of functions, classes, objects and way more are all super well documented. Use this documentation!!
You will probably not understand everything I do the first time you read it or try it out yourself in Houdini. Be patient and dissect every step into smaller chunks. Begin by creating something small and make sure that it works perfect. Then you can start implementing complexer python systems to improve your tool.
Before creating a viewer state let’s first create our UI and the rest of our tool which we will link the viewer state to later on. Don’t worry, this also involves a lot of Python. I will skip the step on how to create the geometry network as you should already be able to do this if you read this. Let’s start with the basics of Python for Houdini digital assets and work our way up from there.
Python Module

The first thing that you should do when considering to enhance your tool using Python is learn about the Python Module. The Python Module is a type of event handler. It can run code whenever the user presses a button, manually enters a value or slides the slider around in the UI. Doing this will trigger and event to which code can be linked in the Python Module. There are other event handlers like OnUpdated which we will be using as well. You can find these event handlers on your HDA under Type Properties > Scripts.
How to link a parameter to a function in the python module? Start off by creating your function. Afterwards go to the parameter that you want to link this function to. In the parameter description under Callback Script we can call our function.
Use hou.phm() to get a reference to the Python Module and after that add the name of the function you created in the Python Module. Add kwargs as an argument. This is a dictionary from which you can get information about the current node, parameter the user changed, etc… . Make sure to set the script language to python.



This kwargs dictionary is super important and we will be using it a lot. What is in this dictionary is dependent on where the function is called from. Sometimes you will get more info than other times.
This is the basic setup, when you now change the parameter the script will run. An easy way to test this is to print some text in your function. You can open the python console to see this text appear
Json vs Multiparameter block

Another super important step that we have to figure out is how we can transfer the data that defines our racetrack from our user interface into our geometry network so we can use regular Houdini nodes to construct the racetrack. But to figure that out we need to first figure out what this data looks like so we might have an idea on how to store it.
Control handles/points

I will only define certain parameters at a couple of points on the racetrack. I will be calling these control handles or control points. The idea is that every point can contain multiple parameters that define how the racetrack looks and plays like at that point. Different points can have different parameters with different values. Looking in Houdini, I found two ways that are mostly used to store this data and then transfer it on to the geometry network.
Multiparameter block

This is a special parameter type that allows you to create multiple instances of the same set of parameters. Every instance in this multiparameter would represent a control handle/point on our racetrack. This would allow us to define per point data (example).


Pros
- Very visual and easy to understand
- All parameters of all the handles are visible at the same time
Cons
- Hard to manage using Python when handles are deleted or added
- Every control handle will contain the exact same set of parameters. For’ some of the control handles we probably only want to change specific parameters like the road width. This however is not possible when using a multiparameter. Every point contains all the parameters. This clutters the UI and is harder to manage.
Json
Using jsons is the other way to transfer data from the user interface to your geometry network. A json allows you to put many different parameters in a single text field. Each element in the json is a dictionary and represents a control handle/point. I will be calling this the handle dictionary. In this dictionary we can define all the per point data using key-value pairs.

Pros
- Easy to manage through python
- You can add handles that only change certain parameters but not others. So the json would only be as big as it needs to be.
- Can save to disk. This would be a super easy way to transfer a racetrack between multiple artist who can work on it.
Cons
- Not as visual and easy to understand as a multiparameter
- Editing a json structure manually is possible but error prone. Therefore, you need another way for the user to change parameter values in the json without having the user edit the json directly.
Conclusion
The multiparameter block is a super nice Houdini feature but it has it’s drawbacks. When we use json on the other hand the possibilities to store our racetrack data are just endless as we are only limited by what Python can do. And python can a lot. So for my tool I decided to work with json to transfer data from the user interface to the geometry network. As I mentioned in the cons about using json, we don’t want an artist to manually change the json. We will need to create a user interface for this so the artist who will use the tool does not have to touch the json to change parameter values.
User interface

Active handle user interface
Because I am using a json structure to transfer my per point data, I need a way for the user of my tool to interact with this json. The first thing I did was add a UI section on my HDA that could show all the values of a single handle dictionary. I will be calling this the active handle from now on.


All handles json
We will need some helper parameters in our user interface. First we need a string parameter that will contain the json. Note, as we do not yet have an option to add and delete control handles (we will add this functionality later) you can always manually edit the json to add a handle dictionary. Beware of typos!

All handle parms
We also need to add a new string parameter which will contain all the parameters that our active handle UI contains. This will be very useful later.

To set this parameter, I created a function in the OnUpdated event handler in the Type Properties > Scripts tab. Here I loop through all the parameters in my main folder and add them to the “All Handle Parms” parameter.

Changing the active handle
The “Active Handle” parameter defines which handle’s values are shown. In the callback script for this parameter I placed the following code: hou.phm().updateActiveHandleParms(kwargs)
. This will call a function that I added to the Python Module.

When the user now changes this parameter, we can get the new value using kwargs["script_value"
]. Using this we can get the dictionary of the new active handle using jsl[index
].. Afterwards I just loop through the keys in this dictionary and set the corresponding parameter to the value of each key. Make sure that the keys match with your parameter names in the UI.

Updating other parameters
On top of this I have another function in my Python Module that takes count of updating one single parameter in the json. I add this function to the callback script of all my parameters except for the “Active Handle” and the “curvePos” as these are both important for something else.

Below you can see this in action. When I change a parameter the callback script is ran and the json is updated. When I change the “Active Handle”, all of the parameters are updated with the correct values from the json.

Handle type
So what is this handle type? The handle type defines what parameters can be changed on that handle. I have a handle type “Normal” where you can only change the road width and rotation. Another handle type “Delete” which allows you to cut away parts of the racetrack. And the last one “Railings” which allows you to add some sort of barrier at the two sides of the track. Because I also added this handle type parameter, I need a way to only show the parameters of the chosen handle type. I set the “Hide When” value of the parent folders (Basic, Delete, Rail) to hide the folder when the handle type is 0, 1 or 2.
Below you can see that only the parameters from one handle type are shown and that all the other parameters are hidden. Note how the json also reflects these changes. I do this with some extra case handling in my code. I delete all the parameters that do not have the correct handle type. I can easily check if the parameter is from a certain handle type because I added Basic__, Delete__ or Rail__ before their names. These prefixes are used as a context for the parameters. You could do without this context, but then you would not have the option to for example have a length parameter under more than one handle type. This is because each parameter has to have a unique name and using these contexts is a neat way to get around that.


Spare parameters
These are optional parameters that the user can dynamically add and remove from the handle dictionary. Spare parameters are also linked to a certain handle type.

Menu Script
You can see that the content of the Spare Parms menu updates according to what is in the Spare Parms list underneath the menu. To do this we first need to create this list. I do this by adding the following code in my updateActiveHandleParms()
function. Every time this function is called it loops through the “All Handle Parms” list. If the parameter is not visible but has the correct handle type, then we add it to the “Spare Parms” list. Later on we set the spare parms string parameter to this list.

Now to update the spare parms menu we need to create an extra function called updateSpareParmsMenu()
. This function will create a list of all the spare parameters.

In the Menu > Menu Script tab set the following code: kwargs["node"].hdaModule().updateSpareParmsMenu(kwargs)
. To make sure that this code runs whenever something changes, we can just manually run this code by using .pressButton()
in the updateActiveHandleParms()
function. This will make sure that the code above is triggered.

Defining spare parameters
To create a new spare parameter, we have to do a couple of things. Let’s first add an extra toggle parameter (see image) with the exact same name + “_hide” at the end. Set the “Hide When” value to hide the parameter when the toggle is 1 (True). You could use node.parm.disable()
for this but Houdini won’t memorize the disabled state of the parameter across sessions. If you want a work around you can make use of toggles.

Under the Action Button tab for this parameter I added the following code: kwargs["node"].hdaModule().deleteSpareParm(kwargs)
. To set the icon for this button you can use the following tag.

I also add the following tag. We will use this later on when we delete spare parameters using viewer states.

Adding and deleting spare parameters
To add spare parameters, I created an extra function addSpareParm()
in my Python Module. This function is added to the Callback Script of the “Add” Button. In this function, I retrieve the parameter that is currently selected in the “Spare Parms” menu. Next, I retrieve the default value for this parameter and lastly, I add this parameter to the active handle dictionary.
To delete spare parameters, I create an extra function deleteSpareParm()
in my Python Module. This function will be called whenever the user presses the “Delete” button. In this function we can get the name of the parameter that should be deleted using kwargs["parmtuple"].name()
. Afterwards, this parameter is removed from the active handle dictionary.
Curve Position
The “curvePos” parameter defines at what arclength value along my racetrack the handle is positioned. This can be a value from 0 to the length of your track.
You could also use a “curveU” value which maps the entire curve between a value from 0 to 1. The downside to using a curveU value is that when you change the length of your curve that the handles will jump around as their position is defined as a percentage of the entire length of the curve. You won’t have this when you define the position as an arclength value.

I created a getCurvePos()
function that gets a list of all the “curvePos” values of all the handles that are in the json. To get the index we can just sort the list and get the index by value. This index represents the position in the json list in which our handle dictionary should be placed.
Changing the curve position
By changing the “curvePos” parameter the corresponding handle will move along. The handles are all ordered in the json list based on their “curvePos” value. So if you change the “curvePos” value then it could be that this order is not correct anymore. To check this I added a function to my Python Module called updateCurvePos()
which I set in the Callback Script of the “curvePos” parameter. This function will call the getCurvePos()
function to get the correct index of this handle. If the index is not equal to the current index of the handle dictionary in the list, then the handle dictionary is removed from the list and inserted back at the correct index.

Adding and deleting handles
The next functionality that we need to add is being able to add and delete handles from our json. To be able to add handles, we need some default values for all our parameters. For this, I created an extra section in my UI.



Whenever the user now clicks on “Add handle”, I construct a dictionary for this handle by looking at the default values. The parameter will only be added to the dictionary if the “Add Default” toggle is True. If there is no toggle the parameter will be added by default. Now at what position in the json do we insert this new handle dictionary? I check at what index in the list the default “curvePos” value should be placed. (see Curve Position). Afterwards I insert the new handle dictionary into the list at this index.
To delete the handle, we can just get the value from the “Active Handle” parameter which will act as our index when deleting a handle from the json using del jsl[index]
.
Creating a python viewer state

So far, we have not yet touched python viewer states. However, all the setup so far has been super important as we will be using a lot of the functions that we created in our Python Module in our viewer state as well.
You can create a brand-new python viewer state by going on your digital asset to Type Properties > Interactive > State Script. Here you click “New” to create a new viewer state. The following pop-up window will appear where you can select some pre-made functions that you would like to use. The ones that I have selected where most useful for me.

Let’s start by assigning some class variables when the user enters the viewer state by pressing “Enter” with their mouse cursor in the viewport. The self.node and self.phm are important variables which we will use a lot. Self.node refers to our HDA node and self.phm refers to our Python Module.

Adding and deleting handles
Now we will add the option to change parameter values by using your mouse and the ability to add and delete handles. For this we will need some keybinds. You can add this right above your __init__ function.

Adding and deleting handles is easy as we have already implemented this in the Python Module. In the onKeyTransitEvent() first get the key that was pressed and afterwards check if this key matches with one of our keybinds. If this is the case press the “Add” or “Delete” button through code.

Selecting handles in the viewport

First get the most important variables from the onMouseEvent(). The following three are used almost always in mouse and keyboard events.

If the user clicked in the viewport then the reason why the onMouseEvent() was trigered will be “Start”. Next we can cast a ray into the scene and collide with a custom geometry from inside our HDA. Afterwards, we can get an id attribute that you have to store on the primitives of the collision geo. This id represents the position of the handle in the json. Using this id we can set the new active handle.


Cycling the active parameter

Up until now I hardcoded the parameter that would be changed when dragging your LMB. But ideally we could replace this with a variable. For this I used the concept of an “Active Parameter”. We need two new parameters for this on our UI. One which will contain the currently active parameter and another which will contain all the parameters that can be cycled through using a keyboard shortcut.


The “Cyclable Active Parms” parameter is automatically set in the OnUpdated event handler. To define if a parameter can be used in this cycle I added a tag to the parameter in the Parameter Description.

In the onUpdated event handler we can now add some code that will check all the parameters in the UI if they have this tag. If so, then they are added to the active parameter cycle.

Now that the setup is done we still need a way to change the active parameter and cycle through the list we just created. I will be using the onMouseWheelEvent() in the python viewer state for this. Don’t forget to add new class variables for the active_parm and the cyclable_active_parms.


Now when you scroll with your MMB, the cycleMode()
function will be called. In this function it is just a matter of getting the active parameter > getting the index of this parameter in the cyclable_active_parms list. Adding the direction to this index > getting the new active parameter from the list > and lastly setting the active parameter to this new one. After that we can cycle through all the cyclable_active_parms, disable all of them and only enable the active parameter.

We can now also use this active parameter as the parameter to change when the user holds LMB and drags. Cycling through the parameters looks like the following.
Updating parameter values
Updating the parameter value by holding LMB and dragging is a bit complexer. Again, tart by getting some of the most important values we can get from the onMouseEvent().

You will still need to add the self.mouse_x_start variable to your class. You can set it using device.mouseX()
when the reason is “Start”. If the reason is “Active” then this means the user is holding LMB and dragging their mouse. When this happens, we want to update our parameter. Let’s get the old value, add the direction and set the new value.

Multiplier tag
At the moment the rate at which the parameter value changes is always one. However, some parameters need to go quicker up and down than others. To define the multiplier for a certain parameter, change the active_parm_cycle tag so it is structured as a dictionary with the multiplier being a key-value pair.

Next in the python viewer state we have to create a new class variable called self.active_parm_tags
. Each time the user enters the state or changes the active parameter, we will call the following function that will set this variable.

If we now calculate the new_value
we can multiple the direction
with the multiplier defined in the self.active_parm_tags
variable. Below, I am changing these values purely by scrolling with my mouse. Note how they all change with different steps. This is because of the multiplier. This way we can also change the handle type through our viewer state if we set the multiplier to one. I also added the functionality to change the value by scrolling with your middle mouse button. Use device.mouseWheel() in the onMouseWheelEvent() to get the scroll direction.

Adding and deleting spare parameters
To do this we need to create some extra keybinds in our class. Add an addSpareParm()
and a deleteSpareParm()
function to the viewer state. To add a spare parameter, just call the addSpareParm()
function from the python module.
To delete a spare parameter first get the currently active parameter and check if this parameter has the “spare_parm = 1” tag. If this is the case then pass the parameter name on to the deleteSpareParm()
function in the Python module to delete it.

Geometry functions
I do this by using something I made myself called geometry functions.
The idea is that using python viewer states we click in our viewport and get the position of where we clicked by colliding with a collision geometry (see selecting handles). This position is stored in a vector parameter in our user interface. This is the input of our geometry function. This position is read into the geometry network and a point is created at this position. I ray the point onto my racetrack curve from which I can get the “curvePos” value. All of the values that I want to use as output for my geometry function I store in a parameter on a single output node. This way I can set the output parameters in the user interface by just grabbing the value from this output node.
To use this geometry function you first have to enter a special mode called “SetParm” using a keyboard shortcut. When you are in this mode, then every mouse action in the viewport will run our special geometry function.

Using Output 0.

Using output 1.

To define what geometry function a parameter should use as you can create multiple geometry functions I modified the “active_parm_cycle” tag. Add a new key-value pair. The key is “SetParm”, I will use this to detect if a parameter even has a geometry function assigned to it as not all parameters will have one. The value consists of three parts. The first one being which geometry function to use. The second is which collision geometry to use. This value is used in another geometry function to switch the collision geometry in my geometry network. And the last part is which output to use.

Below you see the geometry function I created to switch collision geometries. Using python I can set the index in the switch node. This will change which collision is used.

Creating a HUD info panel

This is a new feature since Houdini 19. It allows you to create an info panel linked to your viewerstate. It is meant to explain the most important functionality of your tool. You can create a HUD panel using the following references.
Integration into Unreal Engine
To integrate a tool like this into Unreal Engine you will need to install the Houdini Engine for Unreal plugin. This will allow you to import your Houdini digital assets into Unreal and Unreal will recognize them. The most important parameter on my HDA is the curve input.

I create the shape of the racetrack inside of Unreal using this curve. Afterwards, I open a live connection between Unreal and Houdini using Houdini session sync. Now I am in Houdini and I can start editing my racetrack using the python viewer state that I created.
Reflection
So how did the tool compare when built with and without python viewer states? How did I experience using Python in Houdini?
Well, it was not easy, but still I think it was worth investing my time researching this. I really believe that I created an interactive, user-friendly tool that can benefit a game company if they would want to create a racetrack. Of course my tool can still be refined but that’s not what this research was about. Creating the tool is the hard part. Adding extra options and increasing the graphical quality is the “relatively” easy part. And that is something that I might consider doing in the future.
While creating this tool I learned so much about Python in Houdini. One of the most important things I learned was that you can literally connect every part of Houdini together. At times I felt like I was wrongly using Houdini and Python. For example with the parameter tags to define geometry functions. It almost felt like hacking or abusing the system. But who is to say what the correct way of doing things is? If it is possible and it works, then that is the only thing that matters.
I do have to mention that you can clearly feel that the part of the Houdini object model (HOM) that is used to work with Houdini digital assets is not yet perfect for creating a super interactive, flawless user interface. Quite often I came across bugs or couldn’t find functions to do specific things and I had to find workarounds. If the workaround does its job then you could say that there is no problem at all. However, I would tend to disagree because these workarounds lead to lost time for the developer of the tool and make it more difficult to maintain.
But, this is also part of the process. Houdini and the python integration are in constant development. The only thing that we can do as users of Houdini is give feedback. All the 14 bugs I found I sent to SideFx support. I also sent 5 feature requests of which 3 have already been accepted. When I could not find how to do something I first would experiment, watch tutorials or ask around on forums. When that didn’t work the collaboration with SideFx support went very well.
Is using Houdini engine in combination with Houdini session sync a benefit to the game asset creation pipeline?
There is always the valid recommendation to use as little software as possible when creating a game. This drastically simplifies the pipeline. The more you can do inside of your game engine directly the better. However, I believe that this is not the case when these softwares are limiting your possibilities for creating the best game that you can possibly create. Houdini Engine and Houdini session sync are really good tools to link Unreal Engine and Houdini together. They allow you to tap into all the things that Houdini has to offer. There are still flaws and you will even have crashes, but I am confident this will get better over time. And in general I think that that these tools are way more valuable than a few rough edges here and there.
In general
Bridging the gap between Houdini and Unreal complicates the pipeline and artists will have to learn to work with Houdini and the Houdini tools that tool developers create for them. But, it is absolutely worth to use Houdini. The software is super powerful and flexible as I have demonstrated with my racetrack tool. It is no wonder why more and more game companies are starting to make use of Houdini and all of the benefits that proceduralism brings with it. For me personally the end goal is always to make as much quality content in as little time as possible and make this content available in a game engine as well. Using the combination of Houdini, Houdini Engine and Houdini session sync I am able to do this. I am not paid to say this. I really believe that Houdini will play a bigger and bigger role in the future of game development. In the meantime I will keep learning; keep exploring Python and Houdini and I hope that you could take something away from my research.