Calculate a perpendicular vector from my camera lookat - math

My camera lookat is in a orthographic perspective (much like in a 2D space) it's staring at the ground from top. I'm trying to derive direction so that my character is moving left and right.
Given vector, how can I derive perpendicular vectors? So it can move left and right.

Any 3D vector (not counting zero vectors) have multiple valid perpendicular vectors.
You can calculate a perpendicular vector, by calculating the cross product given 2 non-parallel vectors. So you'd have another vector which to calculate it against, say a reference.
Thus assuming you have a direction/forward vector:
var forward = new THREE.Vector3(0, 0, 1);
Then using another vector such as THREE.Vector3(0, 1, 0). (If y is up, then this would be the upwards unit vector.) Then by calculating the cross product, we can calculate the right direction vector (or left direction by flipping the order or simply negate the right vector):
var right = forward.cross(new THREE.Vector3(0, 1, 0)).normalize();
You can then also get the relative up vector, by doing:
var up = right.cross(forward).normalize();
Which rendered would look something like this. The blue arrow being the forward vector, the red arrow being the right vector, the green arrow being up and the darker green being the reference it's calculated against.
Here's an animated version of the above example.

Related

C#/Unity: Rotating triangles in 3D space to form a 2D polygon

I have some triangles in 3D space, which originate from 0,0,0 and extend towards two points p1= -x0, 0, z0 and p2= +x0, 0, z0. This is in Unity, such that +z is the forward axis (i.e. they lie flat). Each triangle is its own mesh, pivot is at 0,0,0.
Now, I would like to rotate these (using Quaternion.LookRotation) such that their ends form a continuous polygon, in case of three triangles a triangle, in case of four triangles a square, etc.
My approach is to calculate the incircle radius of the resulting polygon based on the length of each triangle (which is 2*x0). If I now calculate n points on this circle (where n is the number of triangles I have), I get x/y coordinates which I can directly use to set the "up" axis of each triangle correctly, i.e. Quaternion.LookRotation(Vector3.forward, new Vector3(x,y,0)). This orients the triangle correctly around the z axis, i.e. the center is still on 0,0,1.
However, and this has me stumped, I still need to change the forward axis of the triangles such that they tilt to form the final polygon. I tried using new Vector3(x,y,z0) which gives an almost correct result, but leads to an overlap at the edges. I suspect this is somehow due to the fact that rotation of the triangles effectively changes z0, but I am not sure how to proceed.
My question is, how to calculate the new forward axis such that the triangles align properly?
The problem is setting the forward axis to (x,y,z0), which is wrong since the length of the vector (x,y,z0) does not equal the original length (which is just z0). The z value thus needs to be adjusted such that new Vector(x,y,z1).magnitude == z0. This can be done by calculating
Mathf.Sqrt(Mathf.Pow(z0, 2) - Mathf.Pow(x, 2) - Mathf.Pow(y, 2))
Problem solved.

Getting perpendicular direction from a direction vector

Given a direction vector from the center of one circle to another, I would like to extract different positions from where a point could go from one circle to another, being the start position perpendicular to the direction vector.
Like in this drawn:
I would like to generate randomly possible paths. Also, can I get the new direction vector of the possible path with just some quick operation using the center to center direction vector?
Thanks!!
One perpendicular vector is:
p = (-v.y, v.x)
You can use this to sample possible start positions:
startPosition = center + normalize(p) * rnd(-radius, radius)
where rnd(a, b) gives a random number in [a, b].
The new direction is then simply:
dir = secondCircleCenter - startPosition

What is the best way to calculate an element's angle when multiple rotates are applied to it

If you do a rotateX(180deg) rotateY(180deg) it's upside down now. So if the mouse is set to move a child element up on drag that child element will now be moving down (depending on how you have things set up).
-webkit-transform: rotateX(?deg) rotateY(?deg) rotateZ(?deg); // where does it point?
ONLY SETUP FOR WEBKIT
Take a look at the fiddle (code is a mess, stripped down). Draw 360 tic marks, arranged in a circle, on your computer monitor. How can you tell what tic mark the arrow is pointing to (assuming the box is at the exact center of the circle)?
A tutorial that covers the basics is here, here.
*edit - the transform-origin being used is at the center of the cube
Note: Everything that follows assumes you are using a vector that passes through the origin, as in this example. In your original example the vector is additionally offset from the origin by the vector [0, 0, 60]. This complicates calculations slightly, so I have used the simplified version in my explanation.
Your vector is currently defined by spherical coordinates Euler angles consecutively applied rotations to a predefined vector. Here is how you can use your rotations to determine the cartesian coordinates of the final vector:
Let us say your vector is [0, 1, 0] (assuming the arrow is 1 unit long and starts at the origin)
Apply x, y and z rotations by multiplying your vector by the rotation matrices described here in any order, replacing θ with the corresponding angle in each case:
                                             
The resulting vector is your original vector transformed by the specified x, y and z rotations
Once you have obtained the rotated vector, finding the projection of the vector on the x-y plane becomes easy.
For example, considering the vector [10, 20, 30] (cartesian coordinates), the projection on the x-y plane is the vector [10, 20, 0]. The angle of this vector from the horizontal can be calculated as:
tan-1(20/10) = 1.107 rad (counter clockwise from the positive x axis)
                    = 63.43 deg (counter clockwise from the positive x axis)
This means the arrow points between the 63rd and 64th "tick marks" counting counter clockwise from the one pointing directly to the right.

How to calculate azimut & elevation relative to a camera direction of view in 3D ...?

I'm rusty a bit here.
I have a vector (camDirectionX, camDirectionY, camDirectionZ) that represents my camera direction of view.
I have a (camX, camY, camZ) that is my camera position.
Then, I have an object placed at (objectX, objectY, objectZ)
How can I calculate, from the camera point of view, the azimut & elevation of my object ??
The first thing I would do, to simplify the problem, is transform the coordinate space so the camera is at (0, 0, 0) and pointing straight down one of the axes (so the direction is say (0, 0, 1)). Translating so the camera is at (0, 0, 0) is pretty trivial, so I won't go into that. Rotating so that the camera direction is (0, 0, 1) is a little trickier...
One way of doing it is to construct the full orthonormal basis of the camera, then stick that in a rotation matrix and apply it. The "orthonormal basis" of the camera is a fancy way of saying the three vectors that point forward, up, and right from the camera. They should all be at 90 degrees to each other (which is what the ortho bit means), and they should all be of length 1 (which is what the normal bit means).
You can get these vectors with a bit of cross-product trickery: the cross product of two vectors is perpendicular (at 90 degrees) to both.
To get the right-facing vector, we can just cross-product the camera direction vector with (0, 1, 0) (a vector pointing straight up). You'll need to normalise the vector you get out of the cross-product.
To get the up vector of the camera, we can cross product the camera direction vector with the right-facing vector we just calculated. Assuming both input vectors are normalised, this shouldn't need normalising.
We now have the orthonormal basis of the camera. If we stick these vectors into the rows of a 3x3 matrix, we get a rotation matrix that will transform our coordinate space so the camera is pointing straight down one of the axes (which one depends on the order you stick the vectors in).
It's now fairly easy to calculate the azimuth and elevation of the object.
To get the azimuth, just do an atan2 on the x/z coordinates of the object.
To get the elevation, project the object coordinates onto the x/z plane (just set the y coordinate to 0), then do:
acos(dot(normalise(object coordinates), normalise(projected coordinates)))
This will always give a positive angle -- you probably want to negate it if the object's y coordinate is less than 0.
The code for all of this will look something like:
fwd = vec3(camDirectionX, camDirectionY, camDirectionZ)
cam = vec3(camX, camY, camZ)
obj = vec3(objectX, objectY, objectZ)
# if fwd is already normalised you can skip this
fwd = normalise(fwd)
# translate so the camera is at (0, 0, 0)
obj -= cam
# calculate the orthonormal basis of the camera
right = normalise(cross(fwd, (0, 1, 0)))
up = cross(right, fwd)
# rotate so the camera is pointing straight down the z axis
# (this is essentially a matrix multiplication)
obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))
azimuth = atan2(obj.x, obj.z)
proj = vec3(obj.x, 0, obj.z)
elevation = acos(dot(normalise(obj), normalise(proj)))
if obj.y < 0:
elevation = -elevation
One thing to watch out for is that the cross-product of your original camera vector with (0, 1, 0) will return a zero-length vector when your camera is facing straight up or straight down. To fully define the orientation of the camera, I've assumed that it's always "straight", but that doesn't mean anything when it's facing straight up or down -- you need another rule.

3D rotations of a plane

I'm doing something where I have a plane in a coord sys A with a set of points already on it. I also have a normal vector in space N. How can I rotate the points on coord sys A so that the underlying plane will have the same normal direction as N?
Wondering if any one has a good idea on how to do this. Thanks
If you have, or can easily compute, the normal vector to the plane that your points are currently in, I think the easiest way to do this will be to rotate around the axis common to the two planes. Here's how I'd go about it:
Let M be the vector normal to your current plane, and N be the vector normal to the plane you want to rotate into. If M == N you can stop now and leave the original points unchanged.
Calculate the rotation angle as
costheta = dot(M,N)/(norm(M)*norm(N))
Calculate the rotation axis as
axis = unitcross(M, N)
where unitcross is a function that performs the cross product and normalizes it to a unit vector, i.e. unitcross(a, b) = cross(a, b) / norm(cross(a, b)). As user1318499 pointed out in a comment, this step can cause an error if M == N, unless your implementation of unitcross returns (0,0,0) when a == b.
Compute the rotation matrix from the axis and angle as
c = costheta
s = sqrt(1-c*c)
C = 1-c
rmat = matrix([ x*x*C+c x*y*C-z*s x*z*C+y*s ],
[ y*x*C+z*s y*y*C+c y*z*C-x*s ]
[ z*x*C-y*s z*y*C+x*s z*z*C+c ])
where x, y, and z are the components of axis. This formula is described on Wikipedia.
For each point, compute its corresponding point on the new plane as
newpoint = dot(rmat, point)
where the function dot performs matrix multiplication.
This is not unique, of course; as mentioned in peterk's answer, there are an infinite number of possible rotations you could make that would transform the plane normal to M into the plane normal to N. This corresponds to the fact that, after you take the steps described above, you can then rotate the plane around N, and your points will be in different places while staying in the same plane. (In other words, each rotation you can make that satisfies your conditions corresponds to doing the procedure described above followed by another rotation around N.) But if you don't care where in the plane your points wind up, I think this rotation around the common axis is the simplest way to just get the points into the plane you want them in.
If you don't have M, but you do have the coordinates of the points in your starting plane relative to an origin in that plane, you can compute the starting normal vector from two points' positions x1 and x2 as
M = cross(x1, x2)
(you can also use unitcross here but it doesn't make any difference). If you have the points' coordinates relative to an origin that is not in the plane, you can still do it, but you'll need three points' positions:
M = cross(x3-x1, x3-x2)
A single vector (your normal - N) will not be enough. You will need another two vectors for the other two dimensions. (Imagine that your 3D space could still rotate/spin around the normal vector, and you need another 2 vectors to nail it down). Once you have the normal and another one on the plane, the 3rd one should be easy to find (left- or right-handed depending on your system).
Make sure all three are normalized (length of 1) and put them in a matrix; use that matrix to transform any point in your 3D space (use matrix multiplication). This should give you the new coordinates.
I'm thinking make a unit vector [0,0,1] and use the dot-product along two planes to find the angle of difference, and shift all your points by those angles. This is assuming you want the z-axis to align with the normal vector, else just use [1,0,0] or [0,1,0] for x and y respectively.

Resources