Procedural 3D sandbox is a tool that aims to combine both real-time procedural modeling and the easy-to-use tools that artists are used to. With this tool, artists have a lot of freedom in creating the procedural models they want while still being able to update them in real-time. With the help of built-in caching and optimized data structures, it is possible to make procedural models that are rather complex.
The main use points for this tool are the creation of real-time animation that isn’t possible with normal techniques like particles or bone animations, furniture that can be adapted based on the users liking, building tools ( for rollercoasters, skate parks, racetracks…) in real-time, world generation and so much more.
Try out the procedural skatepark builder made with this tool (Download)
Features:
- Creation and editing of point, line, and mesh data.
- Easy to use node system for artists.
- Script to easily change parameters in real-time.
- Optimized data structures to make creation and updates as fast as possible.
- Math interpreter to allow for a lot of control in nodes.
Goal
This project was created during an internship at DAE research, the aim of the project was to research how real-time procedural 3D generation could be used in games at runtime. For this research project to be successful, some goals needed to be implemented to the project:
- The tool is able to run in both the editor and at runtime.
- The tool needs to be able to run in real-time to use it for real-time procedural animations.
- Versatility is very important to allow the creation of almost anything that can be thought of.
- Everything has to be user-friendly so artists can use it to create the desired procedural models and programmers have an easy time adding interactions to it.
Editor
To create the complex models that are possible with procedural models, a system is created where points, lines, and meshes can be edited using nodes. Each data type has its own nodes that edit only its own type of data. There are also nodes that can edit every type of data, which are even more versatile than the other nodes.
Node System
The editor is created using a node system. This way it becomes easy for artists to switch from other procedural programs they might use (Houdini, geometry nodes, grasshopper…) to this tool. This way it also becomes easier to maintain the code as each function is completely separated from other functionalities.
A multitude of different nodes exist. There are some general nodes that are useful for each type, for example, transform, copy and transform, add attributes, Merge, scatter points, select input or vertex sort.
Other nodes are more directed to 1 type of node, the point data type has the least amount of functionality only simple nodes like connect points and fuse nearby points are used for point data exclusively.
The data type, has a lot more nodes these vary from reverse line or revolve to triangulate polygon and convert to wire, most of the time, a line is used to be converted to a mesh.
The final data type, meshes, is the most used type. In this data type, a multitude of nodes exist, it contains some simple nodes like, import 3D model and flip polygon to more complex nodes like smoothing groups and uv projections.
Finally there are some nodes that require multiple inputs, for example, the copy to points node requires a collection of points to which it will copy the data from the other input. Another complex node is the sweep node, this node requires an input of a section that is traced over another line.
Parameters
Each node contains 1 or more parameters, this allows the user to customize each node to create the result they want to see. These parameters can vary from very simple types such as integers, floats, vectors, and strings to more complex parameters like 3D models, point collections, and colors.
In these parameters, it is also possible to reference other parameters, this makes the tool perfect to set up a collection of parameters in 1 node which updates the whole node network.
On top of that it is also possible to add attributes to each vertex, these can also be referenced in the parameter field and alow for vertex specific data to be passed through to the next node.
Finally, there is also a parser that can convert the input of a parameter to C# code, this the user to write complex functions inside of a parameter field, which gives even more freedom to the user.
Live Updates
When editing the node network, the user is instantly able to see the end result of what they are creating. When a parameter in the node network is updated, the preview model is updated as well.
Updating Models
The models can be updated during runtime by writing code or by adding a component to the object that automatically changes the 3D model.
A programmer is able to get a reference to the procedural object and can easily pass data to the procedural network to update the 3D model from code, this method allows for a lot of freedom, but also requires the programmer to manage more of the update code.
Another way to update the procedural object, is to add a “Remote Parameter” component to the object, this object only requires the name of the node and variable the user wants to update. When this is setup, the component can be updated using a Unity event, this automatically updates the variable in the procedural object and generates the new procedural model as well.
Optimizations
Data Structures
To optimize the code to work in real time, it was really important to use fast data structures. Mesh data was one of the slowest data types and it was accessed and cloned the most, which made the overall runtime rather slow. To speed up the access to the vertices and mostly the cloning times, I made a single array that contained all indices for each polygon (quad, triangle, triangle fans…), then I created an array that contained the start and end point for each polygon. This way I only had to copy 1 array to copy each polygon instead of having to copy each polygon separately, increasing the speed by a lot.
Caching
Some parts of a node network are never updated, they create simple shapes or combinations of shapes that are reused in the node network. By making a copy of these objects the first time they are created, it is possible to re-use this object when regenerating the procedural mesh. By keeping this copy, often more than half of the network doesn’t need to be updated every time the procedural object is updated. This speeds up the mesh generation considerably as less work has to be executed.
Limited Model Updating
Another way to reduce the load on the CPU, is to not update the model when it is not required. Most of the time, the object is in a static state. In those cases it is not necessary to update the model. In other cases, for example animations or when the object is updated by the user, the object does receive updates until the user stops interacting or the animation is stopped.