How do I think about rotation in the physical and virtual world? - unity3d

I have a couple of IMUs (rotation devices), I'm trying to attach them on fingers and make a glove.
I get confused because I don't have a good way to think about rotation in the physical and virtual world.
Right now, the way I'm thinking about it is that, in the physical world, there is a world coordinate (XYZ). The IMU's rotation quaternion is probably based on that.
I'm also thinking that each IMU has slightly different physical world coordinate from one other (because they give slightly different quaternion values when they point the same direction).
In the virtual world, each IMU has another virtual world coordinate system.
I'm confusing that maybe it's just one coordinate system that cannot be separated as world or virtual? I'm not sure how to think about all of this and it makes it hard to ask questions.
Please tell me which concepts/terminologies I need to understand to
gain intuition about how to think rotations in the physical and
virtual world.
The motivation? I am trying to calibrate my glove (each finger has one IMU, the palm has one IMU) so that it shows correct hand model in the Unity scene. But it's hard to wrap my head around it.

The main concept to understand about how Unity handles the rotation of your object is that every element has a World rotation and a Local rotation.
The local rotation is the rotation of the object relative to it's parent, and the world rotation is the rotation to the object relative to the root of your scene.
Local rotation : https://docs.unity3d.com/ScriptReference/Transform-localRotation.html
World rotation : https://docs.unity3d.com/ScriptReference/Transform-rotation.html
These variables are stored as Quaternions, but if you want to work effectively with them, you will probably want to use Vector3 values. This is what eulerAngles are for :
https://docs.unity3d.com/ScriptReference/Transform-eulerAngles.html
https://docs.unity3d.com/ScriptReference/Quaternion-eulerAngles.html
The Euler angles of your quaternion are actually the XYZ values of your rotation you mentionned in your post.

Related

Why a big moving attractor object gives a slingshot to other object with using gravity formula rather than holding it?

I have a big spherical Gameobject which moves forward in 3D with constant velocity. I have other spherical objects that other big object needs to attract to itself. I am using Newton's law of universal gravitation formula to attract other objects, but as expected, other objects are doing a slingshot movement much like the space shuttles doing when needed with other planets' orbits to accelerate.
I actually want a magnetic effect that without taking the masses into account, all other objects will be catched by the big object. How can I do that? Do I need a different formula? Or do I need to change the movement behavior of the objects altogether?
If I got it right you expect to have something like this: https://www.youtube.com/watch?v=33EpYi3uTnQ
You can do a spherical raycast or have an sphere collider as trigger to detected the objects that are inside of your magnetic field.
Once you know those objects you can calculate the distance from each of them to the magnetic ball.
You can make an inverse interpolation to know how much strength/"magnetism" is getting into that object.
Then you can apply some force on the attracted object towards the magnetic ball's center.
Something like this algorithm:
var objectsInsideField = ListOfObjects;
foreach (o in objectsInsideField) {
var distance = (o.position - center.position).magnitude;
var strength = distance / fieldRadius; // fieldRadius == spherical radius
o.AddForce(dir: o.position - center.position, strength: strength)
}
Of course, you need to do some adjustments and probably add some multipliers to make the force to be meaning.
The final result should be: for each sequential frame, if the object is inside the magnetic field it moves towards the center a bit. The next frame it should be even close to the center so the strength is even bigger.. and so and so.
First of all, since the big objects is moving with constant velocity, a coordinate frame with axes parallel to the axes of the original coordinate system will be moving uniformly with constant velocity, so this new moving coordinate system is also inertial and you can write all your equations of motion in it, calculate everything with respect to it, and at the end you add the uniform movement to the results. The benefit is that the big object is stationary in this coordinate system, so simpler physics applies.
The slingshot effect occurs most likely because your objects are treated as mass-points, rather than bigger 3D entities (like spheres), for which the centers of mass never get too close enough. Hence maybe some sort of collision detection may eliminate this problem, especially if you decrease significantly or kill completely the elastic collision resolution.
All of what I am saying is a bit speculative as I have no access to details.

Moving around the surface of an Earth shaped spheroid in Unity

I'm trying to make a Unity game that allows the user to explore the surface of an Earth shaped spheroid, based on WGS84.
The project so far is on Github, and there's a YouTube video of this behaviour.
A shape the size of Earth is way too big for Unity, so I just spawn tiles near the user, offset so that the first tile is at Unity's origin point. This bit works.
The issue is moving around. I've been using an approach where I get the user's position in ECEF coordinates, then normalise that to provide the global orientation for the player, then I translate the player forward based on that and their rotation.
The issue with this is that normalising the ECEF coordinate means that the player is moving in a spherical shape, but the WGS84 spheroid is not perfectly spherical. So the player sinks into the floor, or flies up if you got south or north, respectively.
My question is, how can I allow the user to move around the surface of the spheroid by way of translation? I feel like there might be some way of taking the major/minor axis of the spheroid into account as the player moves, but I'm not sure how to do that.
I have no experience with Unity or computer graphics, I'm approaching it purely from the navigation point of view.
Let's look at the real world.
We want to travel either by walking/driving on the surface or flying at some altitude. When we do it, we move in the local coordinate system (North-South, East-West, Up-Down), we can't see any curvature. We assume the Earth is flat.
The problem arises when we try to do it on a computer, which is ruthlessly precise and knows the shape of the Earth. We can't assume the Earth is flat, we can't assume the Earth is a sphere. The Earth is a geoid. Fortunately for some purposes we can simplify things and assume the Earth is an ellipsoid. You chose WGS84. Good!
So how to move around an ellipsoid? Solving the problem analitically is a nightmare. We have to cheat ;)
We should assume te Earth is flat for a moment, make a move in a chosen direction in the local coordinate system, write down the altitude of the new position, calculate the global geodetic coordinates (Lat, Long, Alt) of that new point and then replace the altitude with the one obtained while using the local coordinate system. In other words: each time we move forward along a perfectly straight line and diverge from the ellipsoid (just a tiny bit), we force the altitude not to change in relation to the ellipsoid.
Implementation.
You need to be able to freely translate coordinates between geodetic (Lat, Long, Alt) and ECEF. Going from geodetic to ECEF is easy. Finding geodetic coordinates for a given ECEF position is much more complex, there are many different algorithms, I'm sure you should be able to find a ready to use implementation somewhere.
What you also need is Local Tangent Plane, and to be precise, you are going to use NED.
Let's assume your object is initially at some geodetic position. You write down the altitude (relative to the ellipsoid). Then you create a local NED coordinate system with its origin at that point. Then you move the object in that local coordinate system. You write down how much the altitude (or rather the Down coordinate) changed. Then you must calculate the ECEF coordinates of that new position and transform it to geodetic (Lat, Long, Alt). You have the old altitude, you have the altitude change in the NED coordinates, which means you know the new altitude. You then apply that altitude to your new geodetic coordinates (brutally replace the Alt in Lat/Long/Alt with a new value).
Then you make another move in the NED coordinates defined for that new position. And so on...
I'm not sure if it is clear, the process is quite complicated. If you can't understand - shout :)

Unity: Create AnimationClip With World Scale AnimationCurves

I've been looking for a solution to this for quite a while now (meaning several days) and I haven't found anything yet. Maybe I'm thinking about it wrong and there isn't a way, but let's try!
I'm recording hand-data on a Hololens (the Unity Hololens Input Simulation for now). This essentially gives me one float AnimationCurve for each hand joint for each transform.position.x to z and rotation.x to w. Now my goal is to put these curves into an AnimationClip and add it to an AnimatorController (via an AnimatorOverrideController) that animates a hand rig and replay the recordings. Everything so far works!
However, the recorded hand-data from the Hololens is in world scale, not in local scale. (which makes sense, since you usually want absolute coordinates when you want to know where the hand is.) But to animate the hand, it seems I'm only able to set local coordinates, which I don't have.
Example:
clip.SetCurve("", typeof(Transform), "localPosition.x", curve.PositionX);
Here, the clip takes the the x-coordinates from some hand joint and puts it to the localPosition.x of the corresponding hand rig joint. The problem: curve.PositionX is world-scale (absolute coordinates), but localPosition.x takes local-scale (coordinates relative to its parent).
I can't simply change "localPosition.x" to "position.x", like so:
clip.SetCurve("", typeof(Transform), "position.x", curve.PositionX);
even though the Transform class has both properties and position is the object's world scale position. I'm not sure why this doesn't work, but it gives me the following error:
Cannot bind generic curve on Transform component, only position, rotation and scale curve are supported.
I'm aware that it doesn't make much sense to use absolute coordinates for an animation, but I simply don't have anything else.
Does anyone have an approach how I can deal with this in a sensible, not-too-cumbersome way? It seems I have all the important parts, I just can't figure out how to put them together. Thanks so much already! :)
From my basic understanding, it seems like you are using the Input animation recording service provided by MRTK. Unfortunately, MRTK does not provide the localPosition version of Curves data. However, you can modify the data from the recordingBuffer after the InputRecordingService stops recording.
So, this is a method worth trying for you: in the handJointCurves dictionary property of recordingBuffer field, a set of pose curves is stored for each joint. And then, base on this table:Joint pose curves, subtract the position value of the key None from the position value of each other joint in every key frame so that the localPosition based on the key None is obtained.

Move 3d model forwards based on rotation

I have a 3d model in Xcode using SceneKit, that can rotate around itself, and i would like for it to move forwards based on rotation, for example if it is rotated 236 degrees in the z axis, it wouldn't go straight in x or y, but a bit of both so it would move forwards. Is it possible? Do i have to get any plugins?
No plugins required.
You can do this two main ways:
Move the object's position relative to its rotation by changing its "transform" over time.
Applying force (and/or impulses) over time (or instantly) in the direction you'd like your entity to travel.
Within these two approaches are a LOT of other considerations regarding scene size, resistance, speed, immediacy, etc.

LookAt while Hinge Jointed

I do not understand, why jointed object can't look at target.
Example: 2 boxes with hinge joint (anchor is at the touching place) and a target object. When I say A-box to lookAt target, I think it will just turn on X-axis. But both of the boxes start to shake. Why?
Take a moment to reflect on what a call to LookAt is trying to do.
It's rotating the transform while ignoring physics.
That's bound to create problems, since you're not rotating the whole system, you're moving one part of it. Your rotation with LookAt is "fighting" with the adjustments the physics system is trying to make.
To solve that conflict you can do one of the following:
Rotate the entire system (both cubes). This will involve putting them all under one transform, and having that transform rotate.
Use a physics-based approach. It won't be too hard, but won't be as simple as a function call. You'll probably need a simple PID controller such as the one outlined in this thread.