A Signed Distance Field (SDF) Engine built as the dissertation part of my final year project 'A CPU-GPU Pipeline for Real-Time Signed Distance Field Rendering'.
4 months
SDFs allow for boolean operations to be done in real-time.
Various operator nodes can quickly make models look more interesting and can be adjusted in real-time.
The scene is defined on the CPU and is displayed using a tree like structure. Nodes can be re-parented by simply dragging the node onto another and can also deleted and renamed through a right-click context menu.
This window is for editing various properties of the currently selected node in the scene hierarchy. Every node has a local transform as well as parameters based on its information in the type registry. A material can also be applied after being created in the material editor.
The first core component of the engine is the runtime type registry, which defines all available SDF primitives and operations that can be used. Each type is registered with a set of metadata that describes how it should behave, how it is displayed in the editor, and how it is evaluated on the GPU. Adding new types has been made to be fairly straightforward, especially with parameters where different functions can be used that generate the correct metadata.
Below is an example of the registration function for the plane SDF. Unfortunately here I am just referring to the infinite flat surface in 3D space, not the more aerodynamic counterpart.
static void RegisterPlane(SdfTypeRegistry& registry)
{
registry.RegisterType({
.name = "Plane",
.category = SdfTypeCategory::Primitive,
.parameters = {
Param::Float3Norm("Normal", Vector3::Up),
Param::Float("Distance From Origin", 0.0f)
},
.gpuCode = SdfGpuCode::Plane,
});
}
Having a type system like this is important for two main things.
First is so that the editor can be fully data-driven. The properties panel can dynamically generate the correct input UI based on the parameter types and can modify the data directly back into the scene representation. Metadata like the category also allows types to be grouped in the "Add Node" menu.
Second, it makes serialisation much easier as each type and its parameters can be described in a consistent format. This means that scenes can be saved and reconstructed reliably without any hardcoded per-type logic.
In the engine, SDF scenes are defined on the CPU as a hierarchical node graph where each node represents either a primitive or an operator. This hierarchy allows the construction of more complex models through using combination operators on simple SDFs which still being easily modifiable.
Before a scene can be rendered, the CPU-side representation is compiled into a linear representation that can be passed into the GPU shaders. This is required as the scene cannot be passed in while being hierarchical and it also contains data not required on the GPU such as node names.
This project write-up is still being worked on, sorry for the inconvinience.