-
Notifications
You must be signed in to change notification settings - Fork 6
Pipeline
The pipeline framework offers functionality to pipeline a workload efficiently.
It offers some specialized pipeline modules for commonly used tasks.
To keep the application responsive, it works in multiple bursts, between which it pauses the calculation.
A pipeline consists of two components:
- PipelineGraph
- PipelineNode
The pipeline graph manages the workload and contains all PipelineNodes.
The pipeline node has a single task and recieves and/or forwards work items.
To setup a pipeline, one has to create a new pipeline graph instance.
Then the required pipeline nodes have to be setup and added to the pipeline instance.
Lastly, the node connections have to be setup.
If you wanted to replace all existing colliders in a scene with automatically selected colliders, you could create a pipeline like this:
The equivalent pipeline code would look like this:
public PipelineGraph BuildPipeline()
{
// Create the pipeline graph
var graph = new PipelineGraph();
// Create the pipeline nodes
var getGameObjects = new PP_GameObjectCollector();
var meshRendererFilter = new PP_FilterByComponent<Renderer>();
var removeOldCollider = new PP_RemoveComponents<Collider>();
var addCollider = new PP_AddCollider();
// Add nodes to graph
graph.AddNode(getGameObjects);
graph.AddNode(meshRendererFilter);
graph.AddNode(removeOldCollider);
graph.AddNode(addCollider);
// Add node connections
getGameObjects.AddFollowupStep(meshRendererFilter);
meshRendererFilter.AddFollowupStep(removeOldCollider);
removeOldCollider.AddFollowupStep(addCollider);
// removeOldCollider doesn't need a followup step, as it is the last node
return graph;
}
To use the pipeline, one could call it in every update to process a bit of the workload:
public class ReplaceCollidersExample : MonoBehaviour
{
public PipelineGraph graph;
void OnEnable()
{
graph = BuildPipeline();
graph.Initialize();
}
void Update()
{
if(graph == null)
{
return;
}
var hadWork = graph.DoWork(2.0f);
// Remove the graph as it's no longer needed.
if(!hadWork)
{
graph = null;
}
}
[...]
}
This code would collect all game objects in the scene.
Then it filters them by the Renderer component and discards all game objects that don't have a renderer.
Then it removes all Collider components from the game objects.
Finally, it adds an appropriate collider to these game objects.
To keep the application responsive, the pipeline only works for up to 2 milliseconds in every update call.
When the workload has been finished, the graph gets discarded.
All nodes in the above example were specialized nodes.
To create your own specialized node, you can implement it using one of the base classes:
- PipelineBase
The most basic node.
Very flexible, but should only be choosen when no other base node type is sufficient. - PipelineStart
A start node that provides the initial dataset.
Either from a stream, list or other source.
Shouldn't do any work on the items. - PipelineWorker<Tin, Tout>
A simple worker node, that modifies items.
Isn't required to output the same type of items as were recived.
Handles basic item reciving, but has no way of forwarding processed items. - PipelineFilter
A filter that forwards only items that match a filter condition. - PipelineItemWorker
A more specialized version of the PipelineWorker, which outputs the same type of items as recived.
Handles forwarding of processed items. - PipelineItemFactory<Tin, Tout>
A more specialized version of the PipelineWorker, which output different types of items as recived.
Handles forwarding of processed items. - PipelineEnd
The end of a pipeline, can't forward output items.
Can be used as the output of a pipeline.