a better aligntovector?

Blitz3D Forums/Blitz3D Programming/a better aligntovector?

(tu) sinu(Posted 2003) [#1]
aligntovector is causing me a pain with the way how it slowly aligns up ie the closer it gets to the target vector the more it slows down, anyway i can keep it aligning at a consistent rate and not getting slower the closer it comes to it's destination or anyone right a better function(something im trying but am stumped)


Codemonger(Posted 2003) [#2]
I've never used this function but ... looking at the command and assuming it uses interpolation to make smooth or quick transitions, I would guess if you are really close then it would take a longer time to make the transition as opposed to if you are far away ... so you should start with a low rate and then check the distance you are from the vector and the closer you are your rate should be changed closer to 1 ?


Codemonger(Posted 2003) [#3]
I think the aligntovector does a alignment transition between 2 points. So when you move to another spot in essence that is a transition between two totally new points thats why the transition is not smooth, because the rate hasn't changed to reflect the new point. So thats why you need to change the rate as you move, you are dealing with two new points (well one old, one new)... I think ?


(tu) sinu(Posted 2003) [#4]
that's what im trying to do but if i do this

AlignToVector entity,x,0,z,2,align

how would i go about changing the align rate the closer the entity gets to it's target vectors or even figuring out how to.


Codemonger(Posted 2003) [#5]
If you could show some more code that would be great :)


RexRhino(Posted 2003) [#6]
how would i go about changing the align rate the closer the entity gets to it's target vectors or even figuring out how to.


Well, I am not good at this stuff, but I'll take a crack at it:

AlignToVector entity,x,0,z,2,align


could be done as:

AlignToVector entity,x,0,z,2,EntityDistance(entity, target_entity)*k

Where k is come constant.

Wouldn't that work?


(tu) sinu(Posted 2003) [#7]
"If you could show some more code that would be great :) "

i just wanna make my entity align at a constant rate and not get slower the closer it gets to target vector, don't really think anymore code i have relates to this problem, i'll try and see though.

@RexRhino those are things i've been trying but can't seem to get working right, by the way thats measuring a distance between 2 entities not the vectors/direction and won't work for this problem but is in the right area.

imagine my entity facing at -1z vector and aligning to the -1x and +1z vector at a constant rate without changing, i thought something like *align by the difference between the vectors but really don't have a clue and am struggling to think of a way/calculation.


podperson(Posted 2003) [#8]
The way I do it is to figure out where the vector I want to align to is relative to the object I'm aligning (left, right, above, below) and then pivot in the appropriate direction using the controls at my disposal (e.g. a person can turn left or right; a plane can climb / dive).

I don't use aligntovector at all precisely because of the problem you're seeing.


(tu) sinu(Posted 2003) [#9]
"I don't use aligntovector at all precisely because of the problem you're seeing. "

maybe i'll make a request for it in the request forums.


Codemonger(Posted 2003) [#10]
The reason it gets slower the closer you are is because the magnitude has changed due to the distance ... an example would be a 60 degree FOV, well in the distance you could see 1000's of objects and up close you could only see one or two, that fill the screen. So the solution to your problem would be to use a distance formula on the rate. So if we know that our entity is 100 units away from the vector then we know we are 100% away from the vector and our rate would start at the minimum based off of our distance as the distance becomes closer then the rate would increase until we eventually snap into place(1 value) ... so without any programming I would outline the following:

1) StartDistance = 100% = Rate: 0 (known value)
2) CurrentDistance ( variable X) = ?% (unknown value)
3) FinishDistance = 0% = Rate: 1 (snap) (known value)

Forumula =

rate = 1 - (CurrentDistance/StartDistance))

this would interpolate the rate according to the distance so if you are at the object or the intended distance (finish distance) you would have a rate of 1 -- so lets do a math test with made up distances starting at 100:

rate = 1 - (75 units/100 units)
rate = .25

so if you are 75 units aways from your intended target and you started at 100 then the rate would be .25 (works so far)

rate = 1 - (50 units/100 units)
rate = .5

we are now half way there !!

rate = 1 - (0 units/100 units)
rate = 1

we have made it !!! a very smooth transition ...

anyway this is just plain theory, you would have to test it .. don't have a clue if it works heheh :)


DJWoodgate(Posted 2003) [#11]
If you want ten steps I suppose the align value for the first step would be 0.1 (1/10). Now subsequent steps require a larger fraction to keep the step size constant for the remainder. So the value for the next step would be .1111111 (1/9) and so on. I am probably missing something though.


Codemonger(Posted 2003) [#12]
Unfortunately you need some sort of constants that shouldn't be changed because your end goal is to achieve 100% or a rate of 1. this is the same as keyframing in animation (interpolation in between) or motion tweening like in flash. we know our start, we know our finish, so lets let a constant formula fill in the rest.


(tu) sinu(Posted 2003) [#13]
here's a post from sswift which explains it better and in more detail, hope you understand it


"Hey I failed math in high school, and never went to college. I don't even know calculus. :-) So if I can learn this stuff, you can too. You just need to find sources which lay the stuff out in a way that you can understand and then make use of it and you'll learn it over time. I didn't know what the hell a dot product was two years ago, but once I learned, they're really easy to understand, at least, well enough to make use of them in many situations like this. I don't really have an in depth understanding of how the math actually works, but I know what the end result is when you plug in two vectors, and have written the equation down.


This is a dot product:

AdotB# = ax#*bx# + ay#*by# + az#*bz#

You can do a 2D version of it by simply omitting the "+ az#*bz#" from the end.

A and B are vectors. A vector is like a line in space, with one end at 0,0,0, and the other at Vxyz.

If you imagine that your object has a vector that points down the Z axis, and you rotate your object, the end of the vector remains on a sphere as the object rotates. The length of the vector defines the size of that sphere.

Vectors with a length of 1 are called normals. You use normals a lot.

When you do a dot product, the vectors need to be normalized. They need to have a length of 1. Otherwise you won't get a result between -1 and 1.

Now that you know that, this is how to convert an object's orientation into a normal vector in the global coordinate system.

What we're doing here is specifying that we have a vector, ie, normal, ie, line, with a length of 1, pointing down positive Z. Basically just imagine a point at 0,0,1 in object space. That's the end of our normal.

This function converts that point from object space, to world space. In other words, this point is on the nose of our car, so it's always at 0,0,1 in object space, but when we rotate the car so it's nose points up, in WORLD/GLOBAL space, the point will be at 0,1,0, or pointing up the Y axis of the world.

Note that this function does not care where the object is POSITIONED in space, so you can have your obejct anywhere and get the correct result.

TFormNormal Entity, 0, 0, 1
Nx# = TFormedX()
Ny# = TFormedX()
Nz# = TFormedX()

Now we have a normal in world space that tells us which way pur object points.

Do this for both objects.

Then, do a dot product on the two vectors.

As I stated before this is the dot product:
AdotB# = ax#*bx# + ay#*by# + az#*bz#

So you just go:

Dp# = N1x#+N2x# + N1y#*N2y# + N1z#*N2z#


Now that you have Dp#, you know the angle between the two orienations.

If Dp# is 1, then the two vectors point in the same direction. Ie, the two objects point in the same direction. Ie, the angle between the vectors is 0.

If Dp# is 0, then the two vectors are perpendicular. Ie, the angle between the two vectors is 90 degrees. Just like between the X axis and the Y axis. or the X axis and the Z axis.

If Dp# is -1, them the two vectors point in opposite directions. 180 degrees apart. This is the most which two vectors can point away from eachother, whether we do this in 2D, or 3D.

Now that we know how much the two objects point away from eachother, we know how far apart in angle they are seperated.

And because we know that, we know how much aligntovector will rotate the object if we pass it a tween value of 1, or a tween value of 0.5.

Let's say that we want to rotate the objects at 90 degrees per second.

RSpeed# = 90.0

Let's say that the last frame took 200 miliseconds to render.

Time_Delta = 200

Now let's convert that to seconds:

Time_Delta_Sec# = Float(Time_Delta)/1000.0

Now we know that 0.2 seconds elapsed the last frame.
That btw is equivalent to 5 frames per second.

Now that we have the amount of time passed, we know how much we need to move out objects this frame, if we have specified all our speeds in X per second. Meters, degrees, etc.

And we have. We have said out speed is 90 degrees per second.

So, how much do we need to rotate our object this frame?

DeltaAngle# = RSpeed# * Time_Delta_Sec#

Okay, so we now know that we need to move our object 18 degrees this frame.

Now remember our dot product? Dp#?

LEt us say that our objects are seperated by 90 degrees. That means Dp# will be 0.

We know that we need to move 18 degrees this frame, because DeltaAngle# is 18.

And we know that if we pass a tween of 1.0 to AlignToVector, we will move the distance defined by Dp#. Ie, 90 degrees, becuase the objects will rotate to the same orientation instantly with a setting of 1. And we know 0 doesn't rotate them at all.

So, we need the value for Tween#.

Dp# is 0. That means 90 degrees. We can convert DP to degrees like so:

DpAngle# = (-(Dp# - 1.0) / 2.0) * 180.0

Ie, subtract one from Dp# which brings the max down to 0, and the min down to -2. That means now that when the objects point at eachother they're gonna be 0, and when pointing away they will be -2. But we want 1 when pointing away, and 0 when pointing the same. So we invert that to get 0 pointing in the same direction, and 2 pointing away from eachter. Then we divide by 2, so now we have 1.0 when pointing away from eachother, and 0 when pointing the same direction. And finally, we multiply this by 180, to get a value between 0 and 180. And there's our angle.

So now we have DpAngle#, which is 90. We're on the home stretch now!

Okay, so we now know that if we set tween on aligntovector to 1.0, then the objects will rotate 90 degrees.

Okay!

But we only want to move 18 degrees this frame. That's what DeltaAngle# was calculated to be!

So, all we have to do is divide 18 by 90, and we know where 18 is between 0 and 90. Ie, where between 0 and 1 we want to be!

So...

Tween# = DeltaAngle# / DpAngle#

And thus, we know that we need to set the tween on aligntovector to 0.2 this frame to rotate the entity by 18 degrees, which is a speed of 90 degrees per second, because this frame only took 1/20th of a second to run.

Phew!

Now I dare you tell me you still can't implement this! :-) "