PDA

View Full Version : Velocity based on angles



NecroDOME
24-09-2006, 11:05 PM
So, I have a vector (x, y, z) representing angles (in 3D - doh) and a vector velocity (x, y ,z).

For example, if velocity := (10, 0, 0) and the angle := (0, 0, Pi/2), my final vector needs to point up.

Currenly I have this, but I think it's not correct... (tis rotates a point around a point)

function RotateVector(RotatePoint, v, Angle : TD3DVector) : TD3DVector;
var NilPoint : TD3DVector;
begin
NilPoint := VectorSub(v, RotatePoint); // get dist from nilpoint...
v := Nilpoint;

// Z-axis
NilPoint.X := v.X * cos(Angle.Z) - v.Y *sin(Angle.Z);
NilPoint.Y := v.X * sin(Angle.Z) + v.Y *cos(Angle.Z);
v.X := NilPoint.X;
v.Y := NilPoint.Y;

// Y-axis
NilPoint.Y := v.Y * cos(Angle.Y) - v.Z *sin(Angle.Y);
NilPoint.Z := v.Y * sin(Angle.Y) + v.Z *cos(Angle.Y);
v.Y := NilPoint.Y;
v.Z := NilPoint.Z;

// X-axis
NilPoint.X := v.X * cos(Angle.X) - v.Z *sin(Angle.X);
NilPoint.Z := v.X * sin(Angle.X) + v.Z *cos(Angle.X);
v.X := NilPoint.X;
v.Z := NilPoint.Z;

Result := VectorAdd(RotatePoint, NilPoint);
end;


Why I need this? I'm trying to make a helicopter fly :P

JernejL
25-09-2006, 06:43 AM
do this:

normalise your vector so it will have length of 1 (but still point into same direction), then multiply all xyz components of it it by the new length you desire!

NecroDOME
25-09-2006, 09:13 AM
yes... but I still have the same direction... I need to rotate the vector.

btw thanx, I also have some use for that :P

JernejL
25-09-2006, 10:57 AM
yes... but I still have the same direction... I need to rotate the vector.

btw thanx, I also have some use for that :P

to rotate a vector (this is for 2D XY plane only):


procedure RotateVertexXY(var vector; const angle: decimal);
var
COORDS: array[0..1] of single absolute vector;
TEMP: array[0..1] of single;
AFUNC: array[0..1] of single;
anglerad: Single;
begin
TEMP[0]:= COORDS[0];
TEMP[1]:= COORDS[1];

anglerad:= degtorad(angle);

// caching is faster
AFUNC[0]:= Cos(anglerad);
AFUNC[1]:= Sin(anglerad);

COORDS[0]:= TEMP[0] * AFUNC[0] - TEMP[1] * AFUNC[1];
COORDS[1]:= TEMP[0] * AFUNC[1] + TEMP[1] * AFUNC[0];
end;

NecroDOME
25-09-2006, 01:17 PM
in 2D it isn't that difficult... I'm not home now, butt ill try something when I get home.

I post update soon....

JernejL
25-09-2006, 06:25 PM
have you considered using quarternions?

NecroDOME
25-09-2006, 06:44 PM
I have no clue how quarternions work of what they are or how they work.

tpascal
26-09-2006, 04:55 PM
For 3d vectors there is two comun way of doing rotation:
-Using a matrix
-Using a Quaternion.

With matrix you need to store 9 float values but you can do rotations, translations and scale, you can accumulate severals of those operation in a single matrix. If you use APIs like opengl or direct3d then you already have support for work with matrix.

With Quaternions you only need 4 float values, but you can just do rotations with it, (but translation and scale are a trivial calc to do anyway), the big adventage over matrices is that you can do easily the Interpolate operation (called Slerp) between two quaternion, this is a initial rotation and a final rotation and then using a value like 0.5 for get the half way rotation. Quaternion is the preffered way to do skeletal animations in characters; also people say quaternion avoid a problem called Gimbal Lock.

Google for a file unit called GEOMETRY.PAS, which is a collection of useful 3d geometry functions and procedures including matrices and quaternions operations.

anyway here are some of my quaternion procedures:




type
TQuaternion = record
(x, y, z, w: single);
end;


//you have to use this for initialize the quaternion before acumulating rotations.
Procedure QuaternionIdentity(var Q:tquaternion; add:boolean=false);
begin
q.w:=1;
q.x:=0;
q.y:=0;
q.z:=0;
if add then q.w:=0;
end;


procedure QuaternionMultiply(q1,q2:tquaternion; var Qr:tquaternion);
var
_qr:tquaternion;
begin

_qr.w:=q1.w*q2.w-q1.x*q2.x-q1.y*q2.y-q1.z*q2.z;
_qr.x:=q1.y*q2.z-q1.z*q2.y+q1.w*q2.x+q2.w*q1.x;
_qr.y:=q1.z*q2.x-q1.x*q2.z+q1.w*q2.y+q2.w*q1.y;
_qr.z:=q1.x*q2.y-q1.y*q2.x+q1.w*q2.z+q2.w*q1.z;
qr:=_qr;

end;


//angles are in degree!!! not in radians!.
procedure QuaternionSetAxisAngle(var q:TQuaternion; angle:single; const mx,my,mz:single);
var
factor, scaleBy, sinhalfangle: single;
Qa:Tquaternion;
begin

angle:=angle*cpidiv180; //cpidiv180 is a const, convert to radians.

factor := mx*mx+my*my+mz*mz;
if factor=0 then factor := EPSILON;
scaleBy := 1/sqrt(factor);
qa.w := cos(angle/2);
sinHalfAngle := sin(angle/2);
qa.x := mx*scaleBy*sinHalfAngle;
qa.y := my*scaleBy*sinHalfAngle;
qa.z := mz*scaleBy*sinHalfAngle;

quaternionmultiply(qa,q,q); //very important, seem quaternion multiply is not commutative,
//the acumulative quaternion have to be the 2th operand


end;


//warning, result is not accumulative!. we are using here pitch-heading-bank, or (x,y,z) order;

procedure QuaternionSetEulerangles_XYZ(var q:TQuaternion; x,y,z:single);
var
xQ, yQ, zQ:TQuaternion;
begin
QuaternionIdentity(Q);
QuaternionIdentity(xq);
QuaternionIdentity(yQ);
QuaternionIdentity(zQ);

QuaternionSetAxisAngle(xQ,x, 1,0,0);
QuaternionSetAxisAngle(yQ,y, 0,1,0);
QuaternionSetAxisAngle(zQ,z, 0,0,1);

QuaternionMultiply(yQ,xQ,q);
QuaternionMultiply(zQ,q,q);

end;

//same as prior procedure but in this the Result is acumulative, mean if Q already have a rotation then it is acumulated with this another one.

Procedure Quaternion_Rotation_XYZ(var q:TQuaternion; x,y,z:single); //in degrees;
var
q2:tquaternion;
begin
QuaternionSetEulerangles_xyz(q2,x,y,z);
QuaternionMultiply(q,q2,q);
end;

//P1 is a vector, Q is a rotation stored in a quaternion, p2 will get p1 rotated by Q.

Procedure Transform_from_Quaternion(p1:tvector; var p2:tvector; Q:tquaternion);
var
x,y,z,w:single;
begin
x:=q.x;
y:=q.y;
z:=q.z;
w:=q.w;
p2.x:= w*w*p1.x + 2*y*w*p1.z - 2*z*w*p1.y + x*x*p1.x + 2*y*x*p1.y + 2*z*x*p1.z - z*z*p1.x - y*y*p1.x;
p2.y:= 2*x*y*p1.x + y*y*p1.y + 2*z*y*p1.z + 2*w*z*p1.x - z*z*p1.y + w*w*p1.y - 2*x*w*p1.z - x*x*p1.y;
p2.z:= 2*x*z*p1.x + 2*y*z*p1.y + z*z*p1.z - 2*w*y*p1.x - y*y*p1.z + 2*w*x*p1.y - x*x*p1.z + w*w*p1.z;
end;

//you pass a vector which is at absolute position from the origin, then you pass a Q which is already rotated.
//the procedure will return back the absolute vector with the rotation found in the quaternion around the origen.

Procedure Rotation_from_Origin(var v:tvector; const Q:TQuaternion; const origen:tvector);
var
a:tvector;
begin
vectorsubstract(v,origen,a); //substract two vector.
Transform_from_Quaternion(a,a,q);
vectoradd(origen,a,v); //add two vectors.
end;




[/pascal]

Nitrogen
26-09-2006, 05:07 PM
Have a look at one of my projects:

http://www.nitrogen.za.org/projectinfo.asp?id=19

It shows a cylinder made up of vertexes getting rotated around a central point.. How to apply a rotation in a specific axis to a matrix, then how to apply that matrix to the vertex to get it to rotate!

NecroDOME
26-09-2006, 09:12 PM
Yeah, quaternions are exacly what I needed (I not yet understand them, but they work)


Quaternion is the preffered way to do skeletal animations in characters
Still need to implement that in my engine...

JSoftware
27-09-2006, 07:42 AM
(I not yet understand them, but they work)

That's how you are supposed to feel working with quaternions :D

NecroDOME
27-09-2006, 09:23 AM
Ill post a screenshot soon of what I have made...

NecroDOME
27-09-2006, 08:15 PM
1 final question:

How can I rotate a point (vector).

Need it to apply correct forces to fly forward with my helicopter :P (and to rotate te rotor on top)

NecroDOME
28-09-2006, 03:17 PM
UPDATE: I think I got it working...


I still need to know how to rotate a point. I want my helicopter to fly forward (or backward), but can it be done with the quaternions? it's flys up in the correct direction. But if I rotate the helicopter 90 degrees, how can I make it fly forward? it only pitches on the Z axis (local space) but need to transform the movement to global space.

Screenshots I promised:

http://necrodome.homeftp.net/zooi/Helicopter1.jpg
http://necrodome.homeftp.net/zooi/Helicopter2.jpg

3D max rendering
http://necrodome.homeftp.net/zooi/Chopper4.jpg

I need to make the inside of the helicopter and some weapons + skinning...

savage
28-09-2006, 04:53 PM
Looks pretty damn good!

tpascal
28-09-2006, 06:54 PM
I am not sure if i understand well what you want, but if you mean how to rotate your helicopter and move forward to the new direction it is now pointing then it is the same method used for any first person shooters.

* You have a "position" point where you store your current hellicopter position.
* You have a "forward" unit vector like 0,0,1 (if forward mean moving torward the positive Z), every time you add the forward vector to the position your hellicopter move forward one unit.
* you store your current rotations for planes x,y,z like rx,ry,rz. you setup your keyboard for increment/decrement Rx,RY,RZ.

Every time you update your hellicopter new position, you rotate your hellicopter model by rx,ry,rz, using as origin the last position, that will makes your hellicopter head to the desired direction. Then you copy the "forward" vector and you rotate that copy by Rx,Ry,RZ (using as origin always 0,0,0); then you just add this new resulting vector to the last position point for get the new hellicopter position.

You can have more directions vectors like backward, slide_left, slide_right when rotated a copy of them by your acumulated rx,ry,rx then that copy will always point to the relative hellicopter direcion.

hope that help

NecroDOME
28-09-2006, 08:11 PM
I managed to make it fly forward, backward etc, but I can't get the main rotor in place. The position is correct, but the rotation is a little messed up.

NecroDOME
30-09-2006, 11:35 AM
Anyone?

tpascal
30-09-2006, 03:11 PM
It is your main rotor a different mesh?, if so be sure it's bind pose is located at (0,0,0).

your rotor normally will be rotated using the Y plane (if Y mean Up in your engine), but when you rotate the whole hellicopter let's say about Z plane then the rotor is rotated in Y and in Z; so it is important to note the Order used for rotate things, you will not get the same result if you rotate first by Z then by Y than doing Y first then Z. that is why i have procedures like Quaternion_Rotation_XYZ and Quaternion_Rotation_YXZ, etc.

Huehnerschaender
30-09-2006, 04:09 PM
This is taken from FastGeo.
These routines rotate a 3D point around another 3D point (origin).

FastGeo provides many useful calculations for 2D and 3D (so maybe other problems can be solved using it, too).





interface
procedure Rotate(const Rx,Ry,Rz:TFloat; const x,y,z:TFloat; out Nx,Ny,Nz:TFloat); overload;

procedure Rotate(const Rx,Ry,Rz:TFloat; const x,y,z,ox,oy,oz:TFloat; out Nx,Ny,Nz:TFloat); overload;

function Rotate(const Rx,Ry,Rz:TFloat; const Point:TPoint3D):TPoint3D; overload;

function Rotate(const Rx,Ry,Rz:TFloat; const Point,OPoint:TPoint3D):TPoint3D; overload;



implementation

///////////Rotation around axis origin (0,0,0)

procedure Rotate(const Rx,Ry,Rz:TFloat; const x,y,z:TFloat; out Nx,Ny,Nz:TFloat);
var
TempX : TFloat;
TempY : TFloat;
TempZ : TFloat;
SinX : TFloat;
SinY : TFloat;
SinZ : TFloat;
CosX : TFloat;
CosY : TFloat;
CosZ : TFloat;
XRadAng : TFloat;
YRadAng : TFloat;
ZRadAng : TFloat;
begin
XRadAng := Rx * PIDiv180;
YRadAng := Ry * PIDiv180;
ZRadAng := Rz * PIDiv180;

SinX := Sin(XRadAng);
SinY := Sin(YRadAng);
SinZ := Sin(ZRadAng);

CosX := Cos(XRadAng);
CosY := Cos(YRadAng);
CosZ := Cos(ZRadAng);

Tempy := y * CosY - z * SinY;
Tempz := y * SinY + z * CosY;
Tempx := x * CosX - Tempz * SinX;

Nz := x * SinX + Tempz * CosX;
Nx := Tempx * CosZ - TempY * SinZ;
Ny := Tempx * SinZ + TempY * CosZ;
end;
(* End of Rotate 3D Point *)


///////////Rotation around 3D point (x,y,z) -> This may be what you need

procedure Rotate(const Rx,Ry,Rz:TFloat; const x,y,z,ox,oy,oz:TFloat; out Nx,Ny,Nz:TFloat);
begin
Rotate(Rx,Ry,Rz,x - ox,y - oy,z - oz,Nx,Ny,Nz);
Nx := Nx + ox;
Ny := Ny + oy;
Nz := Nz + oz;
end;
(* End of Rotate 3D Point About Origin Point *)

///////////Just other declarations with TPoint3D types
function Rotate(const Rx,Ry,Rz:TFloat; const Point:TPoint3D):TPoint3D;
begin
Rotate(Rx,Ry,Rz,Point.x,Point.y,Point.z,Result.x,R esult.y,Result.z);
end;
(* End of Rotate 3D Point *)


function Rotate(const Rx,Ry,Rz:TFloat; const Point,OPoint:TPoint3D):TPoint3D;
begin
Rotate(Rx,Ry,Rz,Point.x,Point.y,Point.z,OPoint.x,O Point.y,OPoint.z,Result.x,Result.y,Result.z);
end;
(* End of Rotate 3D Point About Origin Point *)


Hope this helps.

Greetings,
Dirk