Convert 2D direction vectors to 3D vectors around sphere
Hi,
I have a set of data with XY velocities (m/s), based upon longitude and latitude data. I am trying to visualize these vectors on a globe. I got very far: However, I keep getting stuck that the vectors point the wrong direction at certain sides of the planet. The planet has been made with spherical coordinates (and the plane version is just lat/lon * 100). East of longitude 0 things start to go horribly wrong.
I am clueless if I need to use complicated math functions or can just use normals/cross/dot products to get things done (much better for performance anyway). But I keep having the wrong direction problem in 3D.
Because of this, I build a 2D version version today, to check if things would work well. After a bit of fiddling around, it seems to work just fine. However, why does it not work on a sphere; if I use the sphere center as a normal to calculate the tangent? I am trying to solve this with normal functions that are easy to port across other languages (so none one of the LookAt , RotateTowards functions etc).
Vector3 normalToCenter = (CenterOfEarth - myPosition);
// Draw normal to earth.
// Debug.DrawLine(myPosition, myPosition + normalToCenter * 60.0f);
// Calculate Tangent to planet.
Vector3 tangent = Vector3.Cross(myVelocity, normalToCenter);
Vector3 newVector = Vector3.Cross(normalToCenter, tangent);
// Draw actual line.
Vector3 finalVector = newVector.normalized * VelocityScale.magnitude;
// For 3D:
Gizmos.DrawLine(myPosition, myPosition + finalVector);
Can someone give some advice? After spending last weekend and every evening this week on this, I am a bit desperate to get it fixed. Help is kindly appreciated.
Example (left 2D, right, 3D):
Thank you for any thoughts and help!
Answer by Captain_Pineapple · Apr 06, 2020 at 01:09 PM
Well just ask yourself this: assume we are at some longitue where it all works. Lets call this longtitude zero. Now you go around the world sphere 180 degrees. if you take a cross product here you do it with the global "toCenter" vector and a non-global vector "myVelocity". which will if you just draw that on a paper result in tangents pointing in different directions even if you take the same "myVelocity"
you need a proper coordinate transformation here. Once transform the position to a sphere. Then rotate the vector by the needed angles. There is already a function for this by multiplication with Quaternions. Another way would be to implement your own rotation matrix. There should be enough material on the internet on this topic.
Answer by Sponge · Apr 06, 2020 at 03:22 PM
Hi @Captain_Pineapple , thank you for your message! Your example makes sense. However I have a bit of a struggle with your advice.
Would you suggest to convert the actual position of the particle point to a spherical coordinate (I assume a unit sphere, so from spherical coordinates to some normalized spherical coordinates) and then calculate the angles based upon the velocity vector? Vector math is not really my thing, but would the problem not be the same, as the velocity would still be based on the original northern/eastward direction? How would I transform this velocity to match with the unit sphere?
Rotation matrices will depend on Sin/Cos functions and I am trying to see if I can solve this with a little of those as possible considering their performance impact. However, if I were to construct one how would you suggest to base the input on (eg. how to determine the angles to put in there?), in order to prevent the same issue as I have now from happening? I have spend quite some time searching for information on this issue and even with my limited math background, and learned a lot from reading university slides and books about atmospheric math / linear algebra in general .
Yet I am struggling to see the full picture to get it done properly - as the amount of different symbols and formula's can be quite overwhelming.
Okay, after all it is no simple topic indeed :D How do you go about transfor$$anonymous$$g your position data at the moment? What information have you given at the code snipped shown in your OP? any angles and so on? do you use sphere coordinates anywhere?
Hi @Captain_PineApple, having no background in math whatsoever I have been overwhelmed with a lot of formulas and symbols the last two weeks. I can program visual things, just not always the math ;). Posting a question is also kind of a threshold because I feel bad enough for it that I cannot figure it out myself after investing many nights and three full days. Therefore it's even more frustrating that it works.. to a certain extent.
So, what I do: I build up my sphere using lat/lon coordinates and transform these to spherical coordinates using commonly used formula:
x = _radius * $$anonymous$$ath.Cos(_polar) * $$anonymous$$ath.Sin(_elevation);
(Z is up).
y = _radius * $$anonymous$$ath.Sin(_polar) * $$anonymous$$ath.Sin(_elevation);
z = _radius * $$anonymous$$ath.Cos(_elevation);
So for a data "particle" (lat/lon value) I use this as well to put a point around the sphere (in XYZ again), except I increase the radius a bit: to make sure we are not going to end up at the sphere surface.
Then I have for these particles a velocity. Say 2m/sec northward, 1m/sec eastward. Which could be Vector3(0.2, 0.1). $$anonymous$$y goal is also to include radius changes (outward) but maybe that is a bit too much next level? (eg: Vector3(0.2,0.1, 0.1)). So in short, no angles are used except for lat/lon to build the XYZ spherical coordinates.
With the earlier mentioned code I can move the particles around, but with the problem that it goes all wrong at a half of the planet.
I have also been trying to transform the particle position back to polar coordinates, and also the velocity particle (and then making the particle have the radius of the point), in order to get a proper rotation value. But somehow that gave numerical instability that things were a bit moving out of their own, even with velocities being zero.
$$anonymous$$y goal is to get it to run on the GPU. I backported my code from the shader to the Vector3 version above to test it directly in Unity (makes debugging quite a bit easier). Hence I also try to work without Quaternion functions and mostly with less "magic" functions (just math operations); but I am sure that I can port such functions to a shader if they make it easy to realize in Unity.
@Captain_Pineapple ; any suggestions based upon the information above? As a long weekend is co$$anonymous$$g up, and being forced to stay inside... perfect time to get this code working :-)! but if you do not have any time, hopefully we can figure it out at some other time :-).
Hey man, sorry was a bit slacking of the last days ^^ But here we go, rotational matrices short lesson No.1:
First we should make sure we talk about the same coordinate system so i'll just lay one down here which should fit the one you use for your coordinates: The world "up axis" is z, Forward is x (so at the 0° long and 0° lat) where as the Side or y-Axis should be at 90° long and 0° lat.
Then we have a short excurse to rotational matrices:
(wanted to post a picture here... wont let me)
So here is a link ins$$anonymous$$d: rotation matrices and stuff
As hopefully shown by the link above there are rotational matrices for the x,y,and z axis. So each matrix represents a rotation about one of the axis by a given angle. the axis you rotate about is defined by the location of the 1. So upper left corner is x-rot and so on...
Now if we imagine the transformation you have to do it is basically the following: You take your current vectorfield and you wrap it around your globe to build a zylinder with _radius. This in return is the same as Taking a rotational $$anonymous$$atrix around the up-vector - so the z-Axis - and multiply it on every vector of your field.
So we take the $$anonymous$$atrix Rz (to represent rotation around Z) and multiply it on your vectors v.
which results in a new vector v' = Rz * v
Now we are basically half way there. Now we need some imagination here: Ins$$anonymous$$d of rotating the vector we have to imagine that the vector stayed where it was but its coordinate system got rotated ins$$anonymous$$d.
And what we need now is a rotation around the y-axis of this new system. Basically Ry v' which can also be written as Ry Rz * v
This again is not completely correct now since the matrix Ry is in relation to our global original coordinate system. I'm gonna shorten this here to: In order to solve this problem we have to switch the order of multiplication: So our final vector v'' = Rz Ry v
If you want to look up as to why this is you are free to do so. basically you should search for something like "coordinate transformation rotation"
now you asked something that might be a bit easier for your cpu but i'm not sure if that exists. What you can do though is cache all sin and cos values somewhere since you always have the same ones on that grid of yours. Perhaps even caching the rotational matrices for each point might be helpful here to do some further optimizations.
feel free to let me know if something was not clear or does not work. I'll try to check in here every now and then (and perhaps a bit earlier than 3 days later ;D)