Dark Bit Factory & Gravity

PROGRAMMING => General coding questions => Topic started by: Kirl on April 26, 2012

Title: 3d angle?
Post by: Kirl on April 26, 2012
Alright so I'm happily clicking away at my keyboard, reformulating 2d math formulas into 3d without much problems until I hit upon a problem.

How do I calculate and define an angle in 3d?

In 2d it's pretty straightforward, I take the x and y distance (dx & dy) and do Math.atan2(dy, dx). I don't know why this works exactly, but it's easy enough to remember. How do I get and define angle between two points in xyz space?
Title: Re: 3d angle?
Post by: hellfire on April 26, 2012
Math.atan2(dy, dx).
I don't know why this works exactly, but it's easy enough to remember.
Because of the unit circle (http://en.wikipedia.org/wiki/Unit_circle).

Quote
How do I get and define angle between two points in xyz space?
acos( angle ) = |v1| dot |v2|
 - where |v| is a normalized vector (means length = 1)
 - "dot" is the dot-product (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z)
 - "acos(a)" is the inverse of cos(a)

Title: Re: 3d angle?
Post by: Kirl on April 26, 2012
Thanks Hellfire, some familiar bits in there. I've ran into the dotprod a nr of times before, looks a lot like getting the distance. I'm not entirely clear on everything yet, probably need a couple more read overs to really sink in. :)

I just got quite a generous helping of extra work on my plate for the comming weeks however, so I'll prolly revisit this at a later time.
Title: Re: 3d angle?
Post by: combatking0 on May 01, 2012
My approach would be to use two angles in the style of coordinates.

The first angle would be on the horizontal plane, relative to the X axis.

The second angle is then measured from the horizontal plane up to the line of elevation.

Hopefully my diagram will be clearer than my explanation.
Title: Re: 3d angle?
Post by: Kirl on May 01, 2012
Thanks CK, that looks pretty straightforward. I guess I could do the movement in sequence as well. Unfortunatly I have a pretty bad cold atm and I'm not feeling very adventurous. I'll give this a try when I'm feeling a bit better. Thanks for the alternate, somewhat more familiar aproach! :)
Title: Re: 3d angle?
Post by: combatking0 on May 01, 2012
I understand - I'm struggling to understand how to put X/Y/Z axes angles into a quaternion, and get the resulting X/Y/Z coordinates out of the other side.

I'm trying to avoid the "gimbal lock" issue caused by using static Euler angles.

My head hurts just thinking about it.
Title: Re: 3d angle?
Post by: hellfire on May 01, 2012
I'm struggling to understand how to put X/Y/Z axes angles into a quaternion, and get the resulting X/Y/Z coordinates out of the other side.
Euler-angles are just axis-angle rotations (http://en.wikipedia.org/wiki/Axis-angle_representation) with an implicitly given axis.
You can describe two consecutive axis-angle rotations as a single rotation around a different axis (just like multiplying two matrices).
Just consider quaternions as a special form of axis-angle with a very useful interpolation operation (http://en.wikipedia.org/wiki/Slerp).
Conversion from axis-angle to quaternion and back is described here (http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle) and here (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm).
When creating quaternions from an axis-angle representation be careful with angles of +/- 180 degrees.
Quaternions can be converted to a rotation matrix (http://www.euclideanspace.com/maths) to transform your vectors conventionally.
Title: Re: 3d angle?
Post by: combatking0 on May 01, 2012
Thanks Hellfire,

I had found another page on one of the websites you have suggested, but it didn't have the information on the pages you have linked to.

I think I'll be able to get it working with this new data. K++
Title: Re: 3d angle?
Post by: combatking0 on May 02, 2012
I have put together a spreadsheet which converts X/Y/Z rotations into a Quaternion, and combines them with the coordinates of a point to give the resulting rotated coordinates after the rotations have been applied.

I will try to summerise my findings in code for the languages I know.

Quaternions in Yabasic anybody?
Title: Re: 3d angle?
Post by: combatking0 on May 03, 2012
Below is the Euler transformation, written in Actionscript:

Code: [Select]
function eulerTransform(x1,y1,z1,xr,yr,zr,xo,yo,zo){
var x2,y2,z2,pts=new Array();
// Rotate about X axis
x2=x1;
y2=y1*Math.cos(xr)+z1*Math.sin(xr);
z2=z1*Math.cos(xr)-y1*Math.sin(xr);
// Rotate about Y axis
y1=y2;
x1=x2*Math.cos(yr)-z2*Math.sin(yr);
z1=x2*Math.sin(yr)+z2*Math.cos(yr);
// Rotate about Z axis
z2=z1;
x2=x1*Math.cos(zr)-y1*Math.sin(zr);
y2=x1*Math.sin(zr)+y1*Math.cos(zr);
// Apply offsets in 3D space
pts[0]=x2+xo;
pts[1]=y2+yo;
pts[2]=z2+zo;
return(pts);
}

And below is the equivalent Quaternion transform, which takes the same arguments:

Code: [Select]
function quaternionTransform(x1,y1,z1,xr,yr,zr,xo,yo,zo){
var xc,yc,zc,xs,ys,zs,qr,q1,q2,q3;
xc=Math.cos(xr*0.5);
yc=Math.cos(yr*0.5);
zc=Math.cos(zr*0.5);
xs=Math.sin(xr*0.5);
ys=Math.sin(yr*0.5);
zs=Math.sin(zr*0.5);
qr=new Array();
qr[0]=xc*yc*zc-xs*ys*zs;
qr[1]=xs*yc*zc+xc*ys*zs;
qr[2]=xc*ys*zc-xs*yc*zs;
qr[3]=xs*ys*zc+xc*yc*zs;
q1=new Array(qr[0],0-qr[1],0-qr[2],0-qr[3]);
q2=new Array(0,x1,y1,z1);
q3=new Array(qr[0],qr[1],qr[2],qr[3]);
q2=qMult(q2,q1);
q3=qMult(q3,q2);
q3[1]+=xo;
q3[2]+=yo;
q3[3]+=zo;
q3.shift();
return(q3);
}

function qMult(m0,m1){
var m2=new Array();
m2[0]=m0[0]*m1[0]-m0[1]*m1[1]-m0[2]*m1[2]-m0[3]*m1[3];
m2[1]=m0[0]*m1[1]+m0[1]*m1[0]+m0[2]*m1[3]-m0[3]*m1[2];
m2[2]=m0[0]*m1[2]+m0[2]*m1[0]+m0[3]*m1[1]-m0[1]*m1[3];
m2[3]=m0[0]*m1[3]+m0[3]*m1[0]+m0[1]*m1[2]-m0[2]*m1[1];
return(m2);
}

The Quaternion code includes a 4*1 Array multiplier, since AS2 lacks the ability to multiply matrices, as far as I know.

I have attached a quick demonstration of the differences which I will include in a tutorial.
Title: Re: 3d angle?
Post by: Raizor on May 03, 2012
That's great CK. A very useful demo. K++
Title: Re: 3d angle?
Post by: jace_stknights on May 04, 2012
heyyyy what strange, I'm just working on this tooo! Got some perspective problems with my 3d rout. I'm using them since the 80's with low resolution. And Actually, i got a very by distort on screen...

The way I'm calculating is like this:

Code: [Select]
; angleX, angleY and angleZ are the rotation in each axis

  C.f = -Sin(angleY)
  F.f = Cos(angleY) * Sin(angleY) ; = (sin x+y + sin x-y)/2
  I.f = Cos(angleY) * Cos(angleX) ;= (cos y+x + cos y-x)/2
  A.f = Cos(angleZ) * Cos(angleY) ;= (cos z+y + cos z-y)/2
  D.f = -Sin(angleZ) * Cos(angleX) + Cos(angleZ) * Sin(angleY) * Sin(angleX)          ; D = (cos z+y-x + cos z-y+x - cos z+y+x - cos z-y-x)/4 - (sin z+x + sin z-x)/2
  G.f = Sin(angleZ) * Sin(angleX) + Cos(angleZ) * Sin(angleY) * Cos(angleX)           ; G = (sin y+x+z + sin y+x-z + sin y-x+z + sin y-x-z)/4 + (cos z-x - cos z+x)/2
  B.f = Sin(angleZ) * Cos(angleY) ;= (sin z+y + sin z-y)/2
  E.f = Cos(angleZ) * Cos(angleX) + Sin(angleZ) * Sin(angleY) * Sin(angleX)           ; E = (sin z+y-x + sin z-y+x - sin z+y+x - sin z-y-x)/4 + (cos z+x + cos z-x)/2
  H.f = -Cos(angleZ) * Sin(angleX) + Sin(angleZ) * Sin(angleY) * Cos(angleX)         ; H = (cos z-y-x - cos z+y+x + cos z-y+x - cos z+y-x)/4 - (sin x+z + sin x-z)/2

; here is the x,y,z axis conversion in 2D
    q.f = 1 -((C*x+F*y+I*z)+Dz)/400
    xplot = (((A*x+D*y+G*z)+Dx)/q)*+ screenw/2
    yplot = (((B*x+E*y+H*z)+Dy)/q)*+ screenh/2

I got at the end the coords for the 2D point. But this way gave me a big distort for big values... Someone got a simple technique for 3D to 2D perspective translation?
Title: Re: 3d angle?
Post by: combatking0 on May 04, 2012
Here's my 3D to 2D converter:

Code: [Select]
function transform2D(x1,y1,z1,zm,sz,xo,yo){
var x2,y2,pts=new Array();
var dv=(z1*zm*0.0125)+1;
x2=sz*(x1/dv)+xo;
y2=-sz*(y1/dv)+yo;
pts[0]=x2;
pts[1]=y2;
return(pts);
}

x1, y1 and z1 are the 3D coordinates of the point.
zm is the Z-Multiplier - I use a value of 40 for this, but you can change it to suit your needs.
sz is the Size Multiplier. Typical values for this can be 50 to 500, depending on the size of your graphic window and the scale of your 3D coordinates.
xo and yo are the 2D offsets. Use these if the 0,0 point of your graphic window is in a corner. OpenGL has its 0,0 point in the centre, so these may be set to 0 for OpenGL.

The output is an array with 2 values. Value 0 is the X coordinate, and value 1 is the Y coordinate.
Title: Re: 3d angle?
Post by: hellfire on May 04, 2012
zm is the Z-Multiplier - I use a value of 40 for this, but you can change it to suit your needs.
That's what they call field of view (http://en.wikipedia.org/wiki/Angle_of_view) in photography (the projection models the attributes of your camera) and it's convenient to describe it as an angle.
Since it's just a 2d-scale it can be multiplied with the transformation matrix beforehand.
So you're just deviding by z in the perspective transform which makes 3d clipping and culling very efficient.
To test if a vertex is inside the view fructum you just have to test:
Code: [Select]
-z > x < +z
-z > y < +z
Title: Re: 3d angle?
Post by: Kirl on May 04, 2012
Hey that is pretty excellent, I've been looking for exactly that as well! Some really good info to process and digist in here, thanks CK0 and Hellfire!

My 3d to 2d screen coord function is as follows, it evolved from Keith Peters code. I like it as I can adjust fl (cam focal length) and the vpX, vpY (vanishing points):

Code: [Select]
function doDepth( xx, yy, zz ) // return screen xy
{
var vScale = fl / (fl + zz);
return { x:(vpX + xx * vScale), y:(vpY + yy * vScale) };
}