Putting a tension into hermite splines

Started by
9 comments, last by Kibble 18 years, 10 months ago
I need to put a tension value into hermite splines, any idea of how to do this? My problem is I'm trying to move RTS units in such a way that the leave their position in the direction they face, turn to their destination, and arrive at the needed orientation, all in one motion. Right now they just spin in place when necessary, it is crappy. Because of this I need a spline that takes two points and the tangents. So either a way to introduce a tension variable into hermite splines, or another type of spline that suits that criteria would be helpful.
Advertisement
This should do what you want:
inline void Vector::hermite( const Vector& from, const Vector& to, const Vector& startdir, const Vector& enddir, float factor ){	float f2 = factor * factor;	float f3 = f2 * factor;	float p1 = 2.0f * f3 - 3.0f * f2 + 1.0f;	float p2 = -2.0f * f3 + 3.0f * f2;	float p3 = f3 - 2.0f * f2 + factor;	float p4 = f3 - f2;	x = from.x * p1 + to.x * p2 + startdir.x * p3 + enddir.x * p4;	y = from.y * p1 + to.y * p2 + startdir.y * p3 + enddir.y * p4;	z = from.z * p1 + to.z * p2 + startdir.z * p3 + enddir.z * p4;}


This is the code for a hermite curve, which could be used for your units movement.
Right, I've got that already. What I need is to figure out how to put a tension in there, so large units make wider turns than small ones. Changing the length of the tangent vectors will change the distribution of points on the spline, will it not? What I really need to do is make the code more robust so it doesn't go crazy when I test things like that for myself. Is this the answer though, or do I need some other stuff to use in the calculation?
I've given up on using hermite splines or any other type of splines for this. At first it sounded good and easy, but it is a really crappy method. I need to figure out some other method of directing units in a smooth path without turning in place. Does anyone have any ideas for this?
Why can't you just turn the unit x*dt degrees towards the target direction each frame? The lower the x-value is, the wider the turn will be.
Of course, but that requires turning in place at the destination to reach the destination direction.

I will explain my problem more: There are a few units that are massive (they aren't constructed at a building, you build them as if it was a building, then when it is done you can use it like a unit). It is necessary to be able to have them facing a certain direction when they arrive at a destination, so they can start shooting quickly. Lets say you wanted to place 2 of these on the edge of your base to defend it, they turn very slowly, so you need to tell them what direction to point so when an enemy unit shows up its facing mostly the right direction. Here is some ascii art (the line shows what direction the unit is facing). Here is what it would do now:
     Start       +---         \             .          \            .           \           .             \          .               \         .               \        .                 \      .                  \    .                   \     .                     \   .                      \   .                       \  .                         +                        / Destination                       /   

Here is what I want it to look like:
     Start       +---           --              \                .                \              .                  \          .                    \       .                       \      .                       \    .                        \   .                          \  .                           \  .                           |                          /                         +                        / Destination                       /   

The picture is crap but hopefully you get the idea. This way, the unit would arrive at the destination in the right direction. Hermite splines fit this well because you just use the start and destination as the two points, and the directions as the tangents. Splines are a bad solution though because they are inflexible, and I have to keep where the unit started from.

I think it is a similar problem of having an airplane take a path so it is lined up with the runway as it lands. The analogy to my current solution would be having the plane go to the start of the approach to the run way in a straight line from its current position, stop in midair, turn to face the runway, then land. I want it all in one smooth motion.

What I need is a routine or function that takes 5 arguments: start position, start direction, destination position, destination direction, and dt. The routine needs to provide the heading and speed for this frame to eventually arrive at the desired destination and direction.

I dont have a proper physics system, so just something that looks good and moves at a certain speed and turning radius (depending on the size of the unit) is fine.

edit: Backslashes are really screwed up.
There is a paper called "Interpolating Splines with Local Tension, Continuity and Bias Control" which explains pretty straight forward how to add tension to a spline in a very simple way. I've used it myself and it's not perfect but it will probably work ok for most purposes. I think it's the same as Kochanek-Bartels splines.
I thought this up a few hours ago.. just didn't have time to write it down for you as I've been at the bathhouse all day =)

well here it goes... untested and probably not bugfree =p (haven't even tryed to compile it myself)

// move() - returns the new direction of the unit// position - units current position// direction - unit vector front vector of unit// targetpos - target position// targetdir - target direction (unit vector)Vector move ( Vector position, Vector direction, Vector targetpos, Vector targetdir ){ Vector dpos = targetpos - position; // angle to targetpos float d = dot(direction, dpos); // targetpos is infront of unit if ( d >= 0 ) {  // angle to targetdir  d = dot(direction, targetdir);  // targetdir is within 90 deg of diretion  if ( d >= 0 )  {   // a vertical plane created from three points (assumes z-axis up)   Plane plane(position, targetpos, targetpos + Vector(0,0,1));   plane.d = 0; // needs to go through origo      // mirror the unit vector targetdir against the plane   d = plane.distance(targetdir);   return targetdir + plane.normal * -d;  }  // targetdir is more than 90 deg of direction  else  {   // just invert targetdir to get the units new dir   return targetdir.inverted();  } } // targetpos is behind unit else {   // turn unit x degrees the shortest way towards targetpos   Vector rotdir; // do some simple trig-magic here =)   return rotdir; }}


This is how I would move my units in a RTS. The func move() should be used to get the new direction of a unit when it is at a certain distance(²) from the targetpos. If it is used when the unit is too far away from its targetpos then it might start to align to targetdir to soon, and that will cause it to take a VERY wide turn.

I will try to compile this later on today to see how it works. Let me know if you want help with the "trig-magic" =)

[edit] note that this only gives a direction in the xy plane and doesn't take into account differences in height(z).

[edit 2] You also need to check if targetpos is reached or surpassed. To assure unit has aligned properly to targetdir just put direction equal to targetdir when it is at its target position

[Edited by - glSmurf on June 19, 2005 11:45:19 AM]
The problem with that is that it only will work horizontally. While I don't need it to work in all 3 axes correctly, the game is underwater and all the units are submarines, so it would be good to have. It seems to me that there should be a relatively nice solution to this.

One idea that I had was to go back to the spline idea but instead of storing where and what direction the unit started from, just make a spline for the current position and direction, and the target position and direction. Then use the standard rotate x amount toward the target idea, toward the middle (parameter wise, ie t = 0.5) of the spline. If I play this out a few steps in my mind it seems to work except for when the unit is very close to the target, in which case I'm going to use turning in place anyways regardless of what method I come up with for this. I think it will work because while the unit is turning around if necessary, the point will force it in that direction, and once it is moving toward the destination the middle of the spline should still push the unit out in such a way that causes it to arrive at the target direction. If I can figure out a way to hack the max turning radius into this, I think it will work well (I think if I just use a low rotate x amount per frame large units could overshoot the target).

This should also be a lot better than my crappy implementation I was using before, which partly involved numerical integration to find the distance along the spline. I think that is why changing the length of the tangents was so unreliable.

edit: Didn't catch your edits, I agree.

Also, it always will turn in place at the destination if necessary, all I'm trying to do is make it so it arrives that way when possible.
Go for TCB splines, which are basically hermite splines, but with the tangents calculated on a way which allow you to set a tension, continuity and bias value per control point.

This topic is closed to new replies.

Advertisement