JR
Josef Rissling
Stories
Code
Sound
About

splines-or-where-s-up-2.jpg
Splines or Where's Up?
Creating a spline editor in Unity for procedural mesh generation.



splines-or-where-s-up-2.jpg
Splines or Where's Up?
Creating a spline editor in Unity for procedural mesh generation.
Spline Editor

I was working on an arcade racer game (like Mario Kart) in Unity, where I missed a built-in spline editor. They were needed for different purposes: for meshes and colliders, for markers (start/finish, time sections etc.), for AI and agents and for testing physics. After looking into various tools in the asset store, I decided to create one myself instead of using one. Besides that the tool would be more customized and easier to use within C#, another bonus would be to understand better how tools in Unity are build.
The Right Spline

The spline would be a list of multiple curves (segments) that share start and ending points. For the curve type my decision felt on , because they are easy to implement and give great flexibility. They are very similar to normal bezier curves but with one extension: Every control point gets additionally a weight, allowing editing as if the points control their "gravity" (influence on the curve).

Two cubic rational bezier curves rendered with different weights:
rational-bezier.svg rational-bezier2.svg
The similarities to a normal bezier curve can be seen in the weights. If all weights are
1
, it behaves like an bezier curve. But if the weights are
higher
, the curve morphs into an linear, sharp-corner style. On the opposite
lower
weights allow just a touch of influence.
Math: Cubic Rational Bezier

Points on a
cubic rational bezier curve
can be computed like below. The start point is on
t = 0
and the end on
t = 1
. For a complete curve multiple points are connected.
float getPointOnCubicRationalBezier ( // point on curve float t, // values float p0, float p1, float p2, float p3, // weights float w0, float w1, float w2, float w3 ) { var bp0 = (1-t)*(1-t)*(1-t)*w0; var bp1 = 3*(1-t)*(1-t)*t*w1; var bp2 = 3*(1-t)*t*t*w2; var bp3 = t*t*t*w3; var weighted = ( p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3 ); var projection = ( bp0 + bp1 + bp2 + bp3 ); return weighted / projection; }
This function can be used for multidimensional curves by calculating every dimension separately.
First Spline

With the help of some tutorials I built my custom tool. After editing my first spline it became clear that the points have a lot of parameters (two 3D tangents plus weights). Since I also wanted to add a twist (up rotation around the curve), I searched a way to reduce the amount of parameters for faster editing. To achieve this, I created an
point edit mode
for every point. It allowed to switch between a
FREE
and
ALIGNED
mode. Whereas
FREE
allows tweaking of every detail,
ALIGNED
mode automatically aligns the (opposite) tangents for smooth transitions of the segments.
unity-spline.jpg unity-spline-inspector.jpg
Curvature

Another way to reduce the parameters is interpolating points to curves, where curves are created by looking at their neighbor points. After researching several models, I found the Kochanek-Bartels spline a very interesting approach. From this spline type, the tension parameter was the inspiration for adding a
TRACK
mode - a point edit mode specialized on building splines for tracks.
TRACK
mode also calculates tangents automatically, but in relationship to its neighbor points. Also a new parameter - named
curvature
- replaces all tangent related parameters and adjusts them all at once.
(For completeness: It has more parameters, but they are used rather in edge cases: e.g. bias and overshoot prevention)

Below two settings of the curvature, the first one with a low and the second one with a high value:
unity-spline-curvature-0.jpg unity-spline-curvature-1.jpg
TRACK
mode reduces greatly the amount of parameters from 8 to 1 and allows quick top-to-bottom editing. First the whole idea can be outlined and later the details can be tweaked.
Mesh generation

Now we can edit the spline nicely. But the spline alone doesn't create meshes. For the mesh generation, several center points and their directions on one curve segment are computed. From those we create 2 border points: one to the left and one to the right. 2 rows of border points result in quads building the whole track.

First image: One curve segment (dotted gray) with centers and directions(red), borders(yellow/pink) and the quads(solid gray).
Second image: A whole track build up by multiple segments.
spline-track-construction.svg unity-spline-mesh.jpg
Where's Up?

But one thing is missing now: the textures. No information of the normal is present right now and you can't say whether a quad is front or back-facing. Although you could just use both sides, you need it for various things - e.g. for gravity in physics. To solve this, a
normal orientation
mode was added for every curve segment. In can be either
DIRECTION
mode, in which any point on the segment faces along a direction. Or it can be
POINT
mode, in which any point faces towards a point.

First: The problem of the possible normals.
Second: The two modes and the normal directions (red: direction, green: point, yellow: same on both):
spline-quad-normal.svg spline-orientation.svg
Auto-Orientation

Although the ability to set the orientation freely is important, I found it not helpful doing it for every segment.
Since the spline is used for creating tracks, a fair assumption are normals in the world up direction. I added it as
Y-SLOPE
mode and assigned it as default
orientation
. Basically, it is the
DIRECTION
mode hard-wired to Y.
Then, another observation led to the 4th mode:
HULL-CENTER
. This mode is similar to
POINT
mode, but hard-wired to the center of the curve hull. It makes sense whenever the normals face inside its own center (e.g. in loops).
But since there is for all
orientation
modes a use case to do the opposite, I added an
FLIP
flag. This allows to "invert" the intention and flip the normals (e.g. facing world down or facing against its center).

First: Visualization of the hull center. Second: FLIP flag on in POINT mode.
spline-orientation-hull-center.svg spline-orientation-flip.svg
The Twist

Now everything is there to assign UVs to the (triangulated) quads including the normal information. The twist parameter is then, after the orientation is clear straight forward. It allows a rotation (of any point on the segment) after the orientation mode and can now be used for subtle or extreme twists. With this (and the auto-orientation) approach the need of an second orientation spline or implicit up orientations indicators is eliminated.

First: Subtle twist, second: extreme twists
Hint: the see-through parts are the back-facing triangles.
unity-spline-track-twist.jpg unity-spline-track-twist2.jpg
Summary

Creating custom tools in Unity is very useful. The spline editing helps in various situations, that would be otherwise time-consuming. The mesh generation works also well, and can be seamlessly built in the normal work-flow. Unfortunately, I couldn't go into all the details, but maybe another time. Send me feedback, if you are curious about one or another thing.
2017 Josef Rissling Contact Terms of Use Nutzungsbedingungen
This site uses cookies. Read more.
Stories
Code
Sound
About