IOS openGL best way to rotate Sphere with touchesMoved - iphone

I drew Globe object using OpenGL and i can rotate it with finger touch , but it doesn't work well in some cases because i am rotating using the difference between x and y
Rotation3D rot = sphere.currentRotation;
rot.x += diffX ;
rot.y += diffY ;
rot.z += 10 ;
sphere.currentRotation = rot;
when you move your finger from Top Right to bottom Left it isn't work good.
Any ideas ?
Thanks
Peter Gabra

To arbitrarily rotate objects, it's easiest to store their current orientation as a transformation matrix and manipulate the elements. I explain this in detail here.
The only difference is that in that other question, the OP wanted to apply rotations from two controls (horizontal and vertical), whereas you are after drag-based rotation. The technique is basically the same, but instead of rotating around either the X or Y axis, you need to compute an arbitrary axis of rotation from the touch's delta vector as follows:
axis = [0, 0, 1] ⨯ [diffX, diffY, 0]
(⨯ = "cross product")
Then you rotate the U, V and W vectors (as described in my other answer) around the axis by some angle in proportion to the length of the delta vector:
M = rotation(k * length([diffX, diffY, 0]), axis)
U = M * U
V = M * V
W = M * W
If you find the object rotating in the opposite direction to what you expect, there are three possibilities:
If it's only the vertical rotation that goes the wrong way, you need to negate diffY. This is a common mistake I make due to inconsistencies between OpenGL and UIKit coordinate systems.
If it's all rotation, you can either swap the arguments in the cross-product or use [0, 0, -1]. This is usually because of confusion between left- and right-handed coordinate systems.
If it's just the horizontal rotation, make both adjustments. (Don't negate diffX, no one uses left-to-right X-coordinates.)

In case you're using Euler angles: I recommend not using Euler angles to model rotations. Use Quaternions instead. It might seem like it makes your code more complicated, but rotations work well when you use Quaternions. Here's some advantages:
it's very straightforward to apply user interaction to current rotation state
no gimbal lock problems
no need for matrix drift adjustments after repeated rotations
you can interpolate rotations easily
Note that Apple give you a Quaternion type to use: GLKQuaternion. No need to write your own Quaternion class.
See also:
http://www.ogre3d.org/tikiwiki/Quaternion+and+Rotation+Primer
Euler angles vs. Quaternions - problems caused by the tension between internal storage and presentation to the user?

Related

Unity Rotate Sphere To Point Directly Upwards Based On Child Point

I've got a 3d sphere which I've been able to plot a point on using longitude and latitude thanks to some work of another developer I've found online. I think I understand what its doing.
What I need to do now is rotate my planet so the point is always at the top most point (ie the north pole) but I'm not sure how to do this. I'm probably missing some important fundamentals here so I'm hoping the answer can assist in my future learning.
Here's an image showing what I have - The blue line is a line coming from the longitude and latitude I have plotted and I need to rotate the planet so that line is basically pointing directly upwards.
https://ibb.co/2y24FxS
If anyone is able to advise it'd be very much appreciated.
If I'm not mistaken, Unity uses a coordinate system where the y-axis points up.
If the point on your sphere was in the xy-plane, you'd just have to determine the angle between the radius-vector (starts in the center of the sphere, ends on the point in question) and the y-axis, and than rotate by that amount around the z-axis, so that the radius vector becomes vertical. But your point is at an arbitrary location in 3D space - see the image below. So one way to go about it is to first bring the point to the xy-plane, then continue from there.
Calculate the radius vector, which is just r = x-sphereCenter. Make a copy of it, set y to zero, so that you have (x, 0, z) - which is just the projection of the vector r on the horizontal xz-plane - let's call the copy rXZ.
Determine the signed angle between the x-axis and rXZ (use Vector3.SignedAngle(xAxis, rXZ, yAxis), see docs), and create a rotation matrix M1 that rotates the sphere in the opposite direction around the vertical (negate the angle). This should place your point in the xy-plane.
Now determine the angle between r and the y-axis (Vector3.SignedAngle(r, yAxis, zAxis)), and create a new rotation matrix M2 that rotates by that angle around the zAxis. (I think for this second one, the simpler Vector3.Angle will work as well.)
So, what you want now is to combine the two matrices (by multiplying them) into a single transform (I'm assuming this is a transformation in the local coordinate system of the sphere, where (0, 0, 0) is the sphere's center). If I'm not mistaken, Unity uses column-major matrices, so the multiplication order should be M = M2 * M1 (the rightmost matrix is applied first).
Reorient your globe using M as a local transform, and it should bring your point to the top. You can also create M3 = M1.inverse, and then do M = M3 * M2 * M1, to preserve the original angular offset from the xy-plane.
Check for edge cases, such as r already being vertical (pointing straight up, or straight down).

Convert coordinate from one world coordinate system to object coordinate system

I am more interested in the mathematics behind this problem, but am using matlab to try and solve this problem. I have an object, positioned using the world coordinate system at (Wx, Wy, Wz)
I would like to calculate the coordinates of this point using the object coordinate system (Ox, Oy, Oz)
To do this, I first need to calculate the axes of the object coordinate system.
Step 1 is to find the Normal (Nx, Ny, Nz)
(assuming that this is not the world z-axis). My object has a yaw, pitch and roll angle applied so I need to find my normal relative to this.
To do this I use a rotational matrix and perform the operations in the order stated above.
Step 2 is to calculate the arbitrary axes.
If abs(Nx < 1/64) and abs(Ny < 1/64)
(Axx, Axy, Axz) = cross product of world y-axis (0,1,0) and the Normal
else
(Axx, Axy, Axz) = cross product of world z-axis (0,0,1) and the Normal
(Ayx, Ayy, Ayz) = cross product of N and Ax
I then scale my arbitrary axes by dividing by the sqrt of the sum of the squares.
Step 3 - Transform the coordinate
To transform the coordinate you point multiply the initial coordinate by each of the axes.
Ox = Wx * Axx + Wy * Axy + Wz * Axz
Oy = Wx * Ayx + Wy * Ayy + Wz * Ayz
Oz = Wx * Nx + Wy * Ny + Wz * Nz
DXF for autocad takes the object coordinates, the Normal vector and a rotation about the normal vector.
This appears to be working reasonable well at positioning the coordinate, but with some issues:
When I use the method above, I find that sometimes my objects are rotated 180 degrees. Digging into this, sometimes the Arbitrary x-axis is negative, sometimes it is positive. This may account for some objects being rotated, but Autocad does not actually reference this Ax vector. It calculates it. This means that I may have to correct this with a rotation about the normal, but I do not what it to always apply (I cannot simply look for a negative value and rotate if negative, as sometimes the object is required to be placed in this direction).I do not know how to overcome this.
If I apply a roll angle to the object and work through this process, the roll angle is not applied correctly. Instead this appears to translate this angle as an Yaw and Site change, but not actually the intended rotation. I cannot see what I have done using the above formula.

Find angle between 2 points ignoring origin.forward in Unity

Background: I am creating an AR treasure hunt app. It is simple, it has a locator that tells you where the treasure is relative to you. I have the camera being the origin and the treasure being an object in AR world.
Question: I would like to rotate my arrow according to where in space the treasure is at. but in 2d. Basically, I would ignore the relative forward plane that is camera.forward.
Example: If the camera rotation is default, the angle can be calculated as atan2(dy,dx). If the camera is looking straight down, the angle is atan2(dz,dx).
What I have tried:
Quaternion lookRot = Quaternion.LookRotation(target.transform.position - origin.transform.position);
Quaternion relativeRot = Quaternion.Inverse(origin.transform.rotation) * lookRot;
Relative rotation is correct in 3d space but I would like to convert that into 2d ignoring the camera.forward plane. So even if the treasure is in front or behind the camera, it should not change the angle.
Okay so I’m hoping this makes sense. You’re going to need some sort of if statement to determine if your character is looking along the x, y or z plane. Hopefully the diagram is clear as to what those parameters are but if not. To be looking in the “x” plane for example, the y rotation would have to be between 45° and -45° or 135° and -135° AND the z rotation would have to be between 45° and -45° or between 135° and -135°.
Essentially what you’ve got is a sphere split into six parts, two parts for each plane along which the character could look. Once you’ve determined which plane the character is looking in you can determine the direction by finding the difference in position between the character and the treasure along the two planes the character isn’t looking along. Then use trig to calculate the angle
Replying to an old thread, but I was struggling with the same problem and found a relatively simple solution:
Project the position of the target (relative to the origin) on a plane defined by the forward vector of the camera. Then just rotate towards the projected point:
Vector3 diff = target.transform.position - origin.transform.position;
Vector3 projected = Vector3.ProjectOnPlane(diff, Camera.main.transform.forward);
origin.transform.rotation = Quaternion.LookRotation(projected);
Calculate the difference in x and y coordinates simply by subtracting transform.x for one object by transform.x of another object and the same process for y coordinates and then use Mathf.atan(difference in y/difference in x) to calculate the angle. Then put the z rotation to this angle and assign the x and y rotation to what they already were.
Turns out there is a very simple way to get relative X and Y of the target.
Vector2 ExtractRelativeXY(Transform origin, Transform target) {
// Get the absolute look rotation from origin to target.
Quaternion lookRot = Quaternion.LookRotation(target.transform.position - origin.transform.position);
// Create a relative look rotation with respect to origin's forward.
Quaternion relativeRot = Quaternion.Inverse(origin.transform.rotation) * lookRot;
// Obtain Matrix 4x4 from the rotation.
Matrix4x4 m = Matrix4x4.Rotate(relativeRot);
// Get the 3rd column (which is the forward vector of the rotation).
Vector4 mForward = m.GetColumn(2);
// Simply extract the x and y.
return new Vector2(mForward.x, mForward.y);
}
Once obtained x and y, turn it into angle using angle = atan2(y,x) as suggested by both MBo and Tom.
This works because of the matrix components of the quaternion can be demonstrated in multiple vectors. Better illustration is found here https://stackoverflow.com/a/26724912.

How to calculate yxy rotation sequence given the quaternion transformation and how to interpret data

Still need the math: I am trying to calculate the yxy rotation sequence given a quaternion transformation. I can easily do this using Matlab's quat2angle function. However, I need to calculate this by hand using a python script.
This part solved: Please look at this awesome presentation which helped me resolve these issues below:
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0CCoQFjAC&url=http%3A%2F%2Fwww.udel.edu%2Fbiology%2Frosewc%2Fkaap686%2Freserve%2Fshoulder%2Fshoulder%2FBluePresentation.ppt&ei=jgRAVLHfOsSrogTJiYHABQ&usg=AFQjCNGFmwh11jEZen80jc3tM4f7HUQcNw&sig2=Dlr8_7TIFPLyUfJy6-pSJA&bvm=bv.77648437,d.cGU
Also, with Matlab, I am seeing strange results with the way they calculate yxy. I have a quaternion transformation of [1.0000 -0.0002 -0.0011 -0.0006] and I get y = 112.4291 x = -0.0719 y1 = -112.5506 (in degrees).
I don't expect to see any rotations here (my sensors aren't rotating). Why is Matlab showing me rotation? And when I try to just move in the x rotation, I see y and y1 also rotate, however, I don't expect y or y1 to be rotating. Any thoughts?
UPDATE:
When I add y + y1 I seem to get the value for the first y (when doing simple rotation around the first y), and this smooths out the data. However, when I combine the three rotations of the shoulder, the data doesn't make sense. I am trying to define shoulder movement based on plane of elevation, elevation and rotation (yxy) in a way that's easy to interpret. When I rotate around x, then the second y, I get "clipping" (data goes to 180 then -180 following positive trend for y1 and opposite happens for y), even though I start my sensors at the zero position. Also, If I try to rotate only around the second y, I see rotation in the x. That doesn't make any sense either. Any additional thoughts?
Note:
I am using 2 IMU sensors, taring them in the same orientation, holding one constant and rotating the other, calculating the relative rotation between them using quaternions, and then calculating the yxy rotation sequence angles.
In case anyone is interested in quaternion calculations and transformations. I solved it using this transformations library:
http://www.lfd.uci.edu/~gohlke/code/transformations.py.html
There are several functions in here using matrices, quaternions, and Euler rotations. And you can convert quaternions to several different Euler rotation sequences. Give thanks to the person who created this script.

device motion in constrained environment

I am trying to solve a seemingly easy problem related to device motion but couldn't figure out how to solve it. I have a situation where iPhone will move in a circle in the x-y plane. I need to find the angle between the iPhone's x and y axes relative to the center of rotation. The iPhone may be in portrait mode or landscape mode or in any angle in between relative to the line connecting iphone to the center of rotation. See the attached picture that explains the scenario.
The yaw change for a given rotation is the same regardless of this angle, so that doesn't really help. I am hoping that there would be some relationship that I can calculate for every small rotation and then find the best fit for the entire motion - but can't figure out that yet.
I appreciate any help or pointers.
(I am writing in pseudo-code since I don't know the API you are using, sorry.)
Here is how to get the axis and angle of the rotation.
Get the rotation matrices R1 and R2 at the beginning and end of your rotation directly from the API (see CMAttitude and CMRotationMatrix). Then, determine the angle and axis of the rotation R that brings R1 to align with R2. You get R as follows:
R = R1 * transpose(R2)
The angle of rotation R is
angle = acos((trace(R)-1)/2)
and its axis is
axis = { R[3][2]-R[2][3], R[1][3]-R[3][1], R[2][1]-R[1][2] }
For further details, please check Rotation matrix to axis angle and also Axis-angle.
I am not sure how to get the angle you are interested in. Nevertheless, I hope that the above helps.
Please don't use roll, pitch and yaw anything other than display. And don't try to integrate them, nothing good will come out.
Anyways, behind the rotation matrices there is integration. In other words, somebody already did the integration for you.