I have added a spline controller to the Unify Community Wiki.
I hope it helps anyone. Any commentary on missing things or how to improve it is very much welcome. For example:
Reparametrize for arc-length, so to allow following it at constant velocity
Make it TCB based (Kochanek-Bartels spline).
Allow for user-edited times in the control points.
A good interface for editing the TCB and times would be to add a component to the control points which has all these params. If this component exits, the SplineController reads it.
Excellent work! Just a few observations, though (you did ask…)
Parametric curves are useful for things other than animation (eg, positioning cones at regular intervals along a roadside without adding them all manually). It would be handy if there was a method that took a fractional position or time and returned a Transform object (ie, position + rotation) for the curve at that point. Also, when I did something like this (less sophisticated, quadratic bezier curves), I found it useful to mark regular intervals of the parameter along the curve in the OnDrawGizmos routine. I used Gizmos.DrawSphere, but it could be done with tick lines or whatever. It is very helpful to be able to read the speed of the curve along its length or to see where objects will be positioned.
When you say “reparameterize” are you talking about varying the size of the parameter step so that longer segments contain more steps than shorter ones? This will help, but as I understand it, this won’t give constant velocity. I think splines are “c^2” curves (constant velocity/accel at segment boundaries) but don’t they vary in velocity along the length of a segment?
Also, regarding the Ease method, would it be possible to use two easing values to do cubic interpolation on the parameter value itself rather than having two sine regions joined by a straight line? (I think quadratic interp is used by Flash for the ease in/out and by Photoshop for the sliders between gradient stops.) I’m not completely sure, but I suspect you could compensate almost exactly for the varying velocity of the curve by choosing the right control values - both the curve and parameter would be interpolated cubically, after all.
Finally, I may be missing something, but the rotational interp doesn’t appear to be using the easing values. Probably best of all would be to allow separate easing for the position and rotation.
(Note that I am not exactly an expert on any of this - ignore me if I am just naively misunderstanding what you are doing!)
Maybe it’s better to separate spline data/rendering and controller into their own components. This way multiple controllers could use the same spline without much overhead.
The line drawing is always drawing on-top which makes it hard to see their actual position in space (i.e. did it penetrate or not?). I wonder if this can be changed?
I also tried to use your scripts for splines I exported from 3ds max. Initially I had dummies without orientation in combination with the tagend-parameter but I had not the orienations like desired. Then I modified my script to created aligned dummies but I am not sure if this really has an effect when using ‘node’ for alignment.
Here is my maxscript (3ds max) to create a parent dummy with one child dummy per spline knot:
-- dominique boutin, 21.01.2008, v1.0
-- select the editable splines where you want a dummy per not
-- select nothing to treat all available editable splines
macroScript SplineToDummies category:"Bogengang" tooltip:"SplineToDummies"
(
-- parse the complete scene when nothing is selected
local collection = #()
if($ == undefined) then
(
collection = $*
)
else
(
collection = $
)
-- declarations
local parentDummy
local bbSize
local splineCount = 0
local splineIndex = 0
local knotsCounts = 0
local knotsIndex = 0
local aSplineNodeDummy
local prefix = ""
-- processing
for anObj in collection do
(
if( classof anObj == line or classof anObj == Splineshape) then
(
-- create parent dummy
bbSize = ( sqrt( distance anObj.max anObj.center))
parent = Dummy name:(anObj.name + "_Root") pos:anObj.center scale:[bbSize,bbSize,bbSize]
-- for every spline in the shape
splineCount = numSplines anObj
for splineIndex = 1 to splineCount do
(
knotsCounts = numKnots anObj
for knotsIndex = 1 to knotsCounts do
(
if(knotsIndex < 10) then
(
prefix = "00"
)
else if (knotsIndex < 100) then
(
prefix = "0"
)
-- position
aSplineNodeDummy = point pos:(getKnotPoint anObj splineIndex knotsIndex ) size:(parent.scale.x*0.4) name:(anObj.name + "_Node_" + prefix + knotsIndex as string)
-- alignment
aSplineNodeDummy.dir = normalize(aSplineNodeDummy.pos - (getOutVec anObj splineIndex knotsIndex))
aSplineNodeDummy.parent = parent
)
)
)
else
(
if( superclassof anObj == shape) then
(
print ("You need to convert " + anObj.name + " to an editable spline for processing.")
)
)
)
)
I am running out of time but I’ll try to post some example splines in FBX format the next time - but you find something.
It does in fact work on the iPhone, but you have to do a lot of editing to get it to work (mainly using a lot of as statements when working with the arrays).
But in my project the spline has to move.
Think about a driving train in which a camera moves on a spline.
Unfortunately that spline controller does not updating the new position of the spline control points.