Swift Scenekit - Multiple rotations - swift

I have an issue with rotating an a node multiple times. I am working on a game with a rolling ball, and while I can rotate the ball along one axis, or two axis by the same amount, I cannot rotate at partial angles.
example:
// Roll right 90 -
SCNNode.pivot = SCNMatrix4MakeRotation(Float(M_PI_2), 0, 1, 0)
// Roll right 180 -
SCNNode.pivot = SCNMatrix4MakeRotation(Float(M_PI_2) * 2, 0, 1, 0)
// Roll up 90 -
SCNNode.pivot = SCNMatrix4MakeRotation(Float(M_PI_2), 1, 0, 0)
// Roll up & right 90 -
SCNNode.pivot = SCNMatrix4MakeRotation(Float(M_PI_2), 1, 1, 0)
All of which will work, however if I need to roll ball right 180 and up 90 I'm stuck.
Even if there was some way to add the vectors together that would do me.
Any help greatly appreciated.

To combine the effects of rotation matrices, use matrix multiplication.
To do that in SceneKit, you can either:
Create separate rotation matrices and multiply them together using SCNMatrix4Mult.
Apply a rotation directly to an existing matrix using SCNMatrix4Rotate. (This is equivalent to the SCNMatrix4MakeRotation + SCNMatrix4Mult option; it just combines those steps into a single function call.)
If the order of transformations is important to your app, remember that matrix multiplication order is the reverse of transformation order.

Related

Rotating rotation value by different normalized vector directions

I have written a script in Unity which takes a SkinnedMeshRenderer and AnimationClip and rotates the vertices in each by a specified number of degrees. It looks mostly correct except that rotations seem to be incorrect. Here is an example bone rotation (in euler angles) in the skeleton along with the correct values that would be needed for the animation to look correct.
With no rotation: (0, 0, -10)
Rotated 90 degrees: (-10, 0, 0)
Rotate 180 degrees: (0, 0, 10)
I have been trying to find a way to rotate these bones to make this conversion make sense with the data I have here, but have come up short. I know I want to rotate these values around the Y axis, but don't actually want the Y value in the euler angle to change. I am aware I could just reorient the root bone around the Y axis and the problem would be solved, but I want to have no rotation in the Y axis. I am "fixing" some older animations that have unnecessary rotation values in them.
var localBoneRotation = new Quaternion(keysX[j].value, keysY[j].value, keysZ[j].value, keysW[j].value).eulerAngles;
var reorientedForward = Quaternion.AngleAxis(rotation, Vector3.up) * Vector3.forward;
localBoneRotation.x *= reorientedForward.x;
localBoneRotation.y *= reorientedForward.y;
localBoneRotation.z *= reorientedForward.z;
var finalRotation = Quaternion.Euler(localBoneRotation);
keysX[j].value = finalRotation.x;
keysY[j].value = finalRotation.y;
keysZ[j].value = finalRotation.z;
keysW[j].value = finalRotation.w;
I have also tried using a matrix and Vector3 but most of the time I end up with values in the Y. Perhaps I am going about this incorrectly. I just need to be able to specify an angle rotation and then have the input data match the final euler angles with each of these data points.

SCNNode Rotation Multiple Axes

This Question was posted, but never answered.
Similar to This Question, I am trying to understand SCNNode.rotation as a 4D vector. The prior question utilizes an example that only manipulates 1 axis, i.e.,
SCNNode.rotation = (0, 0, 1, degToRad(45)) //Rotate about z-axis by 45 degrees
which makes sense; however, what if I wanted to rotate the X axis by 20 degrees, Y axis by 45 degrees and then Z axis by 78 degrees?
SCNNode.rotation = ??
I would provide code I've tried, but I don't understand conceptually the notion of a 4D rotation vector.
Every node just has a transform with 4x4 matrix. So all the rotation operations are reflecting in the changing the transform.
In this case, if you change either of rotation, eulerAngles and orientation, you are supposed to get same value.
If rotating about three axises, I suggested using eulerAngles.
node.eulerAnges = SCNVector3(x:degToRad(20),y:degToRad(45), z:degToRad(78))
After you set this, go back and check to value of rotation:
SCNVector4(x: -0.16975601, y: 0.5943193, z: 0.786109, w: 1.448788)
This means there is an axis going through point(-0.16975601, 0.5943193, 0.786109) and origin (0,0,0), and node is rotating around it for 1.448788 (82 degree).

Getting the difference between two mirrored rotations in Unity

I have two example objects in Unity structured as follows:
EmptyGameObject1: scale(-1, 1, 1)
- Child1: rotation(-4, 167, 179)
EmptyGameObject2: scale(1, -1, -1)
- Child2: rotation(-1, -10, 0)
Now I want to get the difference between the euler angles of the childs considering the scale of its parent. Vector3.Distance returns a quite high value, but I see that the rotation of the childs is very similar in the scene view.
I know that a negative scale of the parent mirrors the child object - but
what does it mathematically do to the rotation?
How can I calculate this rotation difference in unity for x, y and z?
Let's say that var rotation1 = Child1.transform.rotation; and var rotation2 = Child2.transform.rotation; (we're working in world space, right?). We want to find a rotation (let's call it difference) from Child1 to Child2 such that rotation1 * difference == rotation2. This means that we can find it simply by calculating var difference = rotation2 * Quaternion.Inverse(rotation1);. Now that we know the rotation, we can just access it's Euler angles property to determine the x, y and z angles: difference.eulerAngles.x and so on.

Draw Camera Range with Postgis

i am working on some camera data. I have some points which consist of azimuth, angle, distance, and of course coordinate field attributes. In postgresql postgis I want to draw shapes like this with functions.
how can i draw this pink range shape?
at first should i draw 360 degree circle then extracting out of my shape... i dont know how?
I would create a circle around the point(x,y) with your radius distance, then use the info below to create a triangle that has a larger height than the radius.
Then using those two polygons do an ST_Intersection between the two geometries.
NOTE: This method only works if the angle is less than 180 degrees.
Note, that if you extend the outer edges and meet it with a 90 degree angle from the midpoint of your arc, you have a an angle, and an adjacent side. Now you can SOH CAH TOA!
Get Points B and C
Let point A = (x,y)
To get the top point:
point B = (x + radius, y + (r * tan(angle)))
to get the bottom point:
point C = (x + radius, y - (r * tan(angle)))
Rotate your triangle to you azimouth
Now that you have the triangle, you need to rotate it to your azimuth, with a pivot point of A. This means you need point A at the origin when you do the rotation. The rotation is the trickiest part. Its used in computer graphics all the time. (Actually, if you know OpenGL you could get it to do the rotation for you.)
NOTE: This method rotates counter-clockwise through an angle (theta) around the origin. You might have to adjust your azimuth accordingly.
First step: translate your triangle so that A (your original x,y) is at 0,0. Whatever you added/subtracted to x and y, do the same for the other two points.
(You need to translate it because you need point A to be at the origin)
Second step: Then rotate points B and C using a rotation matrix. More info here, but I'll give you the formula:
Your new point is (x', y')
Do this for points B and C.
Third step: Translate them back to the original place by adding or subtracting. If you subtracted x last time, add it this time.
Finally, use points {A,B,C} to create a triangle.
And then do a ST_Intersection(geom_circle,geom_triangle);
Because this takes a lot of calculations, it would be best to write a program that does all these calculations and then populates a table.
PostGIS supports curves, so one way to achieve this that might require less math on your behalf would be to do something like:
SELECT ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')
This describes a sector with an origin at 0,0, a radius of 10 degrees (geographic coordinates), and an opening angle of 45°.
Wrapping that with additional functions to convert it from a true curve into a LINESTRING, reduce the coordinate precision, and to transform it into WKT:
SELECT ST_AsText(ST_SnapToGrid(ST_CurveToLine(ST_GeomFromText('COMPOUNDCURVE((0 0, 0 10), CIRCULARSTRING(0 10, 7.071 7.071, 10 0), (10 0, 0 0))')), 0.01))
Gives:
This requires a few pieces of pre-computed information (the position of the centre, and the two adjacent vertices, and one other point on the edge of the segment) but it has the distinct advantage of actually producing a truly curved geometry. It also works with segments with opening angles greater than 180°.
A tip: the 7.071 x and y positions used in the example can be computed like this:
x = {radius} cos {angle} = 10 cos 45 ≈ 7.0171
y = {radius} sin {angle} = 10 sin 45 ≈ 7.0171
Corner cases: at the antimeridian, and at the poles.

How to move incrementally in a 3D world using glRotatef() and glTranslatef()

I have some 3D models that I render in OpenGL in a 3D space, and I'm experiencing some headaches in moving the 'character' (that is the camera) with rotations and translation inside this world.
I receive the input (ie the coordinates where to move/the dregrees to turn) from some extern event (image a user input or some data from a GPS+compass device) and the kind of event is rotation OR translation .
I've wrote this method to manage these events:
- (void)moveThePlayerPositionTranslatingLat:(double)translatedLat Long:(double)translatedLong andRotating:(double)degrees{
[super startDrawingFrame];
if (degrees != 0)
{
glRotatef(degrees, 0, 0, 1);
}
if (translatedLat != 0)
{
glTranslatef(translatedLat, -translatedLong, 0);
}
[self redrawView];
}
Then in redrawView I'm actualy drawing the scene and my models. It is something like:
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
NSInteger nModels = [models count];
for (NSInteger i = 0; i < nModels; i++)
{
MD2Object * mdobj = [models objectAtIndex:i];
glPushMatrix();
double * deltas = calloc(sizeof(double),2);
deltas[0] = currentCoords[0] - mdobj.modelPosition[0];
deltas[1] = currentCoords[1] - mdobj.modelPosition[1];
glTranslatef(deltas[0], -deltas[1], 0);
free(deltas);
[mdobj setupForRenderGL];
[mdobj renderGL];
[mdobj cleanupAfterRenderGL];
glPopMatrix();
}
[super drawView];
The problem is that when translation an rotation events are called one after the other: for example when I'm rotating incrementally for some iterations (still around the origin) then I translate and finally rotate again but it appears that the last rotation does not occur around the current (translated) position but around the old one (the old origin). I'm well aware that this happens when the order of transformations is inverted, but I believed that after a drawing the new center of the world was given by the translated system.
What am I missing? How can I fix this? (any reference to OpenGL will be appreciated too)
I would recommend not doing cummulative transformations in the event handler, but internally storing the current values for your transformation and then only transforming once, but I don't know if this is the behaviour that you want.
Pseudocode:
someEvent(lat, long, deg)
{
currentLat += lat;
currentLong += long;
currentDeg += deg;
}
redraw()
{
glClear()
glRotatef(currentDeg, 0, 0, 1);
glTranslatef(currentLat, -currentLong, 0);
... // draw stuff
}
It sounds like you have a couple of things that are happening here:
The first is that you need to be aware that rotations occur about the origin. So when you translate then rotate, you are not rotating about what you think is the origin, but the new origin which is T-10 (the origin transformed by the inverse of your translation).
Second, you're making things quite a bit harder than you really need. What you might want to consider instead is to use gluLookAt. You essentially give it a position within your scene and a point in your scene to look at and an 'up' vector and it will set up the scene properly. To use it properly, keep track of where you camera is located, call that vector p, and a vector n (for normal ... indicates the direction you're looking) and u (your up vector). It will make things easier for more advanced features if n and u are orthonormal vectors (i.e. they are orthoginal to each other and have unit length). If you do this, you can compute r = n x u, (your 'right' vector), which will be a normal vector orthoginal to the other two. You then 'look at' p+n and provide the u as the up vector.
Ideally, your n, u and r have some canonical form, for instance:
n = <0, 0, 1>
u = <0, 1, 0>
r = <1, 0, 0>
You then incrementally accumulate your rotations and apply them to the canonical for of your oritentation vectors. You can use either Euler Rotations or Quaternion Rotations to accumulate your rotations (I've come to really appreciate the quaternion approach for a variety of reasons).