SDF Atlas
SDFs as a technique for rendering have seemingly unbounded potential in terms of the kinds of implicit geometries and input transforms you have at your disposal.
However, authoring these SDFs tends to require a decent understanding of math, and GPU shader languages.
Even if you are comfortable with that, editing and iterating a text based shader file to output a visual result leave much to be desired.
This project seeks to create a tool that allows for the authoring of simple SDF compositions in a graphical environment as well as demonstrate a couple fun use cases.
SDF Primer
You really can't talk about SDFs without mentioning Inigo Quilez, his videos, and articles as it's due to his excellent work that myself, and many others, started experimenting with rendering SDFs
So, getting into it, an SDF, also called a signed distance function or signed distance field, is a function where for a given position in space, it returns a signed distance from an implicit boundary where the sign indicates whether the position is inside or outside the boundary
By convention:
A negative distance is inside the boundary,
A distance of 0 is exactly on the boundary,
A positive distance is outside the boundary
For composing SDFs
Given 2 SDFs, the SDF of their union can be constructed by evaluating the 2 SDFs and returning the result of their minimum
With that, now all you need to start rendering SDFs are some primitives -> https://iquilezles.org/articles/distfunctions2d/
I would highly recommend experimenting with these, Shadertoy being an obvious choice
While doing so, you may find, as I did, that manipulating shapes, their position, and properties through text leaves a lot to be desired.
Say you rendered a pretty basic scene as below.
Now lets say that bottom triangle looks a little to big.
- Well, which
SD_Tri(...)
is it? - Which vertex param do you need to change?
- What values are you going to change it to?
Really, all you want to do is point and drag.
Implementing this isn't to hard, we can test control points first to give priority
As for the SDFs, well we already know how to evaluate an SDF given a position, so let's just pass in the mouse position.
Track a little state, apply some translations, add a bit of visualization and... voilà
Ok, but what's this 'Atlas'?
Where there's one, there's many
~ Mike Acton
Quick detour:
If we're rendering textures on the GPU, it's likely we're going to be using more than just 1 texture.
Well, if they're all the same dimension we could use a texture array.
If that's not the case could alternatively pack them all into one texture atlas.
Given that this project is about SDFs and not textures, and we're not going to be limiting their dimensions
I think it's fitting to name it an SDF Atlas
So while we have plenty of ways to create a texture and render it by calling say:
R_Image(image_rect, image_id, color_tint);
This project seeks to implement a way to create an SDF and render it at a similar high level by calling say:
R_SDF(sdf_rect, sdf_id, color_main, color_border, ...); // other params will come in handy later ;)
How'd it go?
Here is the SDF editor demonstrating
-
SDF Primitives:
- Capsules
- Rectangles
- Triangles
-
SDF Warps:
- Reflection
- Grid Repetition
- Angular Repetition
-
Scaling
-
Rounding
-
Copy/Paste
-
Undo/Redo
So that's the SDF side of it, let's explore the Atlas aspect
A common use of texture atlases is to have a particle system, so here's a particle system that uses SDF Atlas entries
If you look closely, you might notice the particles blending their shapes.
Well, no need to squint, here's a timeline for visualizing the interpolation of SDF Atlas entries
And finally, a custom shader which uses the SDF Atlas entries to render a lava lamp kind of effect
https://gfycat.com/slowoilyindianringneckparakeet
the gif file was to large :(
but maybe this preview will be convincing enough to follow the mysterious gfycat link ;)
What's Left
So much.
This project barely scratches the iso-surface of the depth that SDFs have to offer.
Just the editor alone could have:
- More Primitives (c'mon, I only get 3?)
- More structure (initially planned on having an additive, subtractive, and mask layer but it was cut for scope)
- Even more structure (you can only warp 1 SDF primitive once, ideally, this would be completely arbitrary)
- More warps (the repetitions are way to rigid for my taste)
- More math (would really like to be able to parametrize the SDF params themselves with noise functions)
- Time param (Having time as a parameter would make these entries much more lively and dynamic
- Compile to HLSL (if you want the performance, this is a necessity)
- Bi-directional (Modifications to GUI editor compile to HLSL, modifications to HLSL are reflected back to GUI editor)
- Better controls (like seriously, only a sleep-deprived programmer could think this was okay)
Elephant in the room, we're only using 2 of our n-dimensions...
n > 2 was cut for scope ;)