# 3DNeed help rotating a 3D ring

#### Misu

##### The forum's immigrant
Ive gotten stuck on this for a week now and I cant bust my head on doing this properly...

Im trying to trace random spheres around an origin point but that can rotate in both x and y axis.

Ive gotten one direction moving perfectly (y axis)...

But I cant come up with one for the x axis that can adapt with the previous y axis rotation.
Ive tried several ways to work on this but I cant seem to get it working how I wanted.

This is the script thats functional for y axis (I am using d3d_draw just for placeholder until I get the mechanic working):

Code:
``````for(i = 0; i<360; i+=360/8)
{
xx = lengthdir_x(16,i);
yy = lengthdir_y(16,i);
zz = 20;
//////y axis
dir = floor(((i+90) mod 360)/180)*180;
rot = dx mod 360;//rotation
ang = (1-abs(floor(((i+90) mod 360)/180)*2))*rot;

//var nx = lengthdir_x(point_distance(0,0,xx,0),point_direction(0,0,xx,0));
var ny = lengthdir_y(point_distance(0,0,0,yy),point_direction(0,0,0,yy));
var nz = zz; var l1 = point_distance(0,ny,xx,yy);
var vx = ((-cos(dir*pi/180)*cos(ang*pi/180))*l1);
var vy = ny+((sin(dir*pi/180)*cos(ang*pi/180))*l1);
var vz = nz+(sin(ang*pi/180)*l1);

d3d_draw_ellipsoid(vx-1,vy-1,vz+1,vx+1,vy+1,vz-1,-1,1,1,20)
}``````
Any help on performing this and improving it would be great, please

#### hippyman

##### Member
Why not just use the d3d_transform functions? They work just as well with 2D stuff as they do with 3D stuff.

I do want to mention that this is still pretty neat with the code that you used. I always like seeing cool math stuff like this.

I went ahead and put this together to show you what I mean. I used draw_circle but had the issue with the 2D being rotated like a plane so I used draw_ellipsoid just so it always looks like a circle.

You can rotate it with W-A-S-D-Q-E keys

https://www.dropbox.com/s/sta3yxoj8ouafxt/circles.gmz?dl=0

Last edited:

#### sp202

##### Member
Look into spherical coordinates.

#### Misu

##### The forum's immigrant
I do want to mention that this is still pretty neat with the code that you used. I always like seeing cool math stuff like this.
Thank you, I made the whole thing myself and didnt took me a while to thought it out.

TBH, I cant use d3d_transform functions for two reasons...

1. Im moving this eventually to GMS2.
2. I need an algorithm that can return me the coordinates so I can store all the xyz points in a buffer during create event.

Thats why Im not using the transformation functions because it only manipulates any drawing but doesnt return me the value of it.

Look into spherical coordinates.
You got to elaborate more than that because its not helpping. I looked it up and it seems too confusing. Ironically, Im not a programmer genius you know
If you could explain better than how they do online, I would appreciate it.

#### jo-thijs

##### Member
Thank you, I made the whole thing myself and didnt took me a while to thought it out.

TBH, I cant use d3d_transform functions for two reasons...

1. Im moving this eventually to GMS2.
2. I need an algorithm that can return me the coordinates so I can store all the xyz points in a buffer during create event.

Thats why Im not using the transformation functions because it only manipulates any drawing but doesnt return me the value of it.
You can still use the d3d_transformation functions then, you'll just have to implement them yourself.
This shouldn't be too hard, it should just be performing a 4x4 matrix multiplication.
You'll then only need to figure out what matrix you need to multiply with.
In the case of y-axis or x-axis rotation matrices, these are very simple and easy to look up.

You got to elaborate more than that because its not helpping. I looked it up and it seems too confusing. Ironically, Im not a programmer genius you know
If you could explain better than how they do online, I would appreciate it.
Do you know about polar coordinates?
Spherical coordinates are just a simple extension of those to a 3D space.
Working in the XY-plane, you can identify a line L going through the origin by its counterclockwise angle with the x-axis.
If you then consider the plane through L and the z-axis, you can identify a half-line in that plane starting the origin by its counterclockwise angle with L.
Once you've done that, you've described an arbitrary half-line in space by 2 angles.
You can now identify any single point P in 3D space by providing the 2 angles of the half-line starting at the origin and going through P
and by providing the distance between the origin and P.
You've now described P in terms of 2 angles and a distance.

I'm not sure how helpful this would be though.

This is the script thats functional for y axis (I am using d3d_draw just for placeholder until I get the mechanic working):

Code:
``````for(i = 0; i<360; i+=360/8)
{
xx = lengthdir_x(16,i);
yy = lengthdir_y(16,i);
zz = 20;
//////y axis
dir = floor(((i+90) mod 360)/180)*180;
rot = dx mod 360;//rotation
ang = (1-abs(floor(((i+90) mod 360)/180)*2))*rot;

//var nx = lengthdir_x(point_distance(0,0,xx,0),point_direction(0,0,xx,0));
var ny = lengthdir_y(point_distance(0,0,0,yy),point_direction(0,0,0,yy));
var nz = zz; var l1 = point_distance(0,ny,xx,yy);
var vx = ((-cos(dir*pi/180)*cos(ang*pi/180))*l1);
var vy = ny+((sin(dir*pi/180)*cos(ang*pi/180))*l1);
var vz = nz+(sin(ang*pi/180)*l1);

d3d_draw_ellipsoid(vx-1,vy-1,vz+1,vx+1,vy+1,vz-1,-1,1,1,20)
}``````
Any help on performing this and improving it would be great, please
I don't get why you're using dir and ang and I'm not sure what dx is.
Can you elaborate on how your code works if you want us to give an answer that builds further upon it?

#### TheSnidr

##### Heavy metal viking dentist
GMC Elder
The matrix_build function lets you create a transformation matrix with rotation around the x, y and z axes.

#### Misu

##### The forum's immigrant
Ok let me explain again. I know how to do the transformations using the typical d3d_transform AND matrix_build as well... but I cant use those for what Im doing because I need to get the xyz position of the final transformation of these points when applied. Basically, what I am looking for is exactly a raw calculation on doing xyz axis rotation so not only I can apply the transformation but I can also get the xyz value base on the transformation with the relative position. Yal showed me online on matrices but I still cant get my head on properly doing the math for this.

The closest I could get was this but its still doesnt work. Im not a total genius on calculus tbh,
Code:
``````dz = 0;
var rx1 = 1;
var rx2 = cos(dx)-sin(dx);
var rx3 = sin(dx)+cos(dx);
var ry1 = cos(dy)+sin(dy);
var ry2 = 1;
var ry3 = -sin(dy)+cos(dy);
var rz1 = cos(dz)-sin(dz);
var rz2 = sin(dz)+cos(dz);
var rz3 = 1;
for(i = 0; i<360; i+=360/8)
{
xx = lengthdir_x(16,i);
yy = lengthdir_y(16,i);
zz = 20;
// ll = point_distance(0,0,xx,yy);
var vx = xx * (rx1*rx2*rx3);
var vy = yy * (ry1*ry2*ry3);
var vz = zz * (rz1*rz2*rz3);
d3d_draw_ellipsoid(vx-1,vy-1,vz+1,vx+1,vy+1,vz-1,-1,1,1,20)
}``````

#### hippyman

##### Member
Basically, what I am looking for is exactly a raw calculation on doing xyz axis rotation so not only I can apply the transformation but I can also get the xyz value base on the transformation with the relative position
So you want the distance between the center point and each circle? Could I ask what for?

#### Bart

##### WiseBart
You can transform each of the vertices using d3d_transform_vertex() (or matrix_transform_vertex() in GMS2) and prepare the transformations using matrix_build() and matrix_multiply().
That way, you can store the individual vertices in an array or list, and get the transformed vertices using that function.

Something like this:
Code:
``````var trf_rotx = matrix_build(...);
var trf_roty = matrix_build(...);
var trf_combined = matrix_multiply(rotx,roty);
matrix_set(matrix_world,trf_combined);         // Transform using this matrix
for(var i = 0;i < array_length_1d(untransformed_verts);i++) {
var vtx = untransformed_verts[i];
transform_verts[i] = d3d_transform_vertex(vtx[0],vtx[1],vtx[2]);
}``````

#### Misu

##### The forum's immigrant
You can transform each of the vertices using d3d_transform_vertex() (or matrix_transform_vertex() in GMS2) and prepare the transformations using matrix_build() and matrix_multiply().
That way, you can store the individual vertices in an array or list, and get the transformed vertices using that function.

Something like this:
Code:
``````var trf_rotx = matrix_build(...);
var trf_roty = matrix_build(...);
var trf_combined = matrix_multiply(rotx,roty);
matrix_set(matrix_world,trf_combined);         // Transform using this matrix
for(var i = 0;i < array_length_1d(untransformed_verts);i++) {
var vtx = untransformed_verts[i];
transform_verts[i] = d3d_transform_vertex(vtx[0],vtx[1],vtx[2]);
}``````
This actually might do the trick.

According to the help document, it appears to do what I am looking forward to. However, it seems very unclear to me on usage. Is there a more better example or explanation on this?

#### jo-thijs

##### Member
Ok let me explain again. I know how to do the transformations using the typical d3d_transform AND matrix_build as well... but I cant use those for what Im doing because I need to get the xyz position of the final transformation of these points when applied. Basically, what I am looking for is exactly a raw calculation on doing xyz axis rotation so not only I can apply the transformation but I can also get the xyz value base on the transformation with the relative position. Yal showed me online on matrices but I still cant get my head on properly doing the math for this.

The closest I could get was this but its still doesnt work. Im not a total genius on calculus tbh,
Code:
``````dz = 0;
var rx1 = 1;
var rx2 = cos(dx)-sin(dx);
var rx3 = sin(dx)+cos(dx);
var ry1 = cos(dy)+sin(dy);
var ry2 = 1;
var ry3 = -sin(dy)+cos(dy);
var rz1 = cos(dz)-sin(dz);
var rz2 = sin(dz)+cos(dz);
var rz3 = 1;
for(i = 0; i<360; i+=360/8)
{
xx = lengthdir_x(16,i);
yy = lengthdir_y(16,i);
zz = 20;
// ll = point_distance(0,0,xx,yy);
var vx = xx * (rx1*rx2*rx3);
var vy = yy * (ry1*ry2*ry3);
var vz = zz * (rz1*rz2*rz3);
d3d_draw_ellipsoid(vx-1,vy-1,vz+1,vx+1,vy+1,vz-1,-1,1,1,20)
}``````
Still no explenation of your own code.

Matrices will probably be the easiest method, although quaternions might be even slightly better.

The idea behind matrices is the following.

Suppose you've got the following 2 vectors in 3D space: (1, 0, 0) and (0, 1, 0).
Before rotation, the centers of every sphere in your ring can be described as a linear combination of these 2 vectors: (X, Y, 0) = X * (1, 0, 0) + Y * (0, 1, 0)
You now want to perform an euclidean transformation (a rotation) on your space.
Every euclidean trasformation can be proven to be the combination of a linear transformation on a finite vector space and a translation.
Every linear transformation on a finite vector space can be shown to be equivalent to a matrix multiplication with the column matrix containing the coordinates of the vector.

The center of your ring has coordinates (0, 0, 0) and after the transformations, it will still be (0, 0, 0).
From this, you can conclude that the translation part can be skipped in your case and all you're left with is a matrix multiplication.

Since the z-coordinate is initially always 0, it suffices to work with a 3 x 2 matrix, one that maps 2 coordinates onto 3 coordinates.
You're now looking for a transformation that looks like:
Code:
``````[a b]   [x]
[c d] * [y]
[e f]``````
When you let x = 1 and y = 0, the result of this transformation is (a, c, e).
This is what the vector (1, 0), the one going to the right in 2D should get mapped to in 3D.

Analogously, when you let x = 0 and y = 1, the result is (b, d, f), which is what the vector (0, 1) gets mapped to.

We now consider a rotation around the x-axis (like you've already done) over an angle of theta.
The vector (1, 0) then gets mapped to (1, 0, 0), so a = 1, c = 0 and e = 0.
The vector (0, 1) gets mapped to (0, cos(theta), sin(theta)), so b = 0, d = cos(theta) and f = sin(theta).

For our euclidean transformation, we need to map 3 coordinates to 3 coordinates however.
This means we'll have to determin a 3 x 3 matrix transformation of the form:
Code:
``````[a b u] [x]
[c d v] [y]
[e f w] [z]``````
We only need to determin u, v and w.

Since we are working with euclidean transformations, there is a property stating that the transpose of the matrix, multiplied with the matrix itself must be the identity matrix.
We thus get the following equations:
Code:
``````a*a + c*c + e*e = 1
a*b + c*d + e*f = 0
a*u + c*v + e*w = 0
b*b + d*d + f*f = 1
b*u + d*v + f*w = 0
u*u + v*v + w*w = 1``````
Getting back to the transformation around the x-axis over an angle theta, these equations become:
Code:
``````1*1 + 0*0 + 0*0 = 1 (OK)
1*0 + 0*cos(theta) + 0*sin(theta) = 0 (OK)
1*u + 0*v + 0*w = 0 (So u = 0)
0*0 + cos(theta)*cos(theta) + sin(theta)*sin(theta) = 1 (OK)
0*u + cos(theta)*v + sin(theta)*w = 0 (So v = -tan(theta)*w)
u*u + v*v + w*w = 1 (So w² = 1 / (1 + (tan(theta))²) = (cos(theta))²)``````
This has as solution u = 0, v = -sin(theta) and w = cos(theta).
(there is also a property of rotation matrices stating that their determinant must be 1, which makes the above signs (- for sin and + for cos) the only correct ones).

We've now got the complete rotation transformation around the x-axis.

Analogously for the rotation around the y-axis, you'd get:
a = cos(theta), c = 0, e = sin(theta),
b = 0, d = 1, f = 0,
u = -sin(theta), v = 0, w = cos(theta)

Here's an example of the implementation of all of the above in GML: