I have 2 vectors, lets say vector $a$ and vector $b$. I want to rotate vector $a$ to face more in the direction of vector $b$, but I want to have some maximum angle of the rotation. For example, if $a$ would be $(0, 0, 1)$, $b$ would be $(0, 1, 0)$ and the maximum angle 45°, I want to output $(0,\sqrt{0.5},\sqrt{0.5})$. I can do it in 2D, but I need it in 3D and there I have a problem with limiting the rotation to the angle. Is this possible in some way, that isn't much processing-heavy?
Rotate vector to face more in the direction of another vector
rotationsvectors
Related Solutions
What I understand is that the rotation should rotate the vector $u$ to a vector $u'$ pointing in the direction of the positive $z$ axis.
In the usual interpretation of what a vector is in $\mathbb R^3,$ the vector $u$ does not actually have a particular start or end point; it merely gives a direction and distance; but you can perfectly well specify the vector $u$ by specifying two points, $\newcommand{\startp}{\mathit{start}\,}\startp$ and $\newcommand{\endp}{\mathit{end}\,}\endp$, and taking the differences in those points' coordinates to get the coordinates of $u.$ Moreover, once you have a rotation that makes the image $u'$ point in the positive $z$ direction, the same rotation will take $\startp$ to a point $\startp'$ and take $\endp$ to a point $\endp'$ such that if you name the $x,y,z$ coordinates of these points by using the subscripts $x,y,z$ then \begin{align} \endp_x' &= \startp_x', \\ \endp_y' &= \startp_y', \\ \endp_z' &= \startp_z' + \lVert u\rVert > \startp_z'. \\ \end{align} This seems to match your sketch.
Assuming that rotation matrices are applied on the left side of a vector (the usual convention), the function that you have chosen to use, $$ M_{\mathit{rot}} = M_{Z} M_{Y}M_{X},$$ performs the $Z$ rotation last. This rotation preserves the angles that vectors make with the $z$ axis, so if we are to get $u'$ parallel to the $z$ axis we are not going to do it with this last step; we must do it with the rotations around the $x$ and $y$ axes instead.
The rotation around the $y$ axis will not be able to "correct" any difference in the $y$ coordinates of the start and end points, so we need the first rotation, the one around the $x$ axis, to rotate the points to the same $y$ coordinate. We do this by rotating $u$ to a vector parallel to the $x,z$ plane; that is, eliminate its $y$ coordinate.
You can consider a rotation around the $x$ axis to leave all $x$ coordinates unchanged but to rotate the projections of points on the $y,z$ plane. The projection of $u$ on the $y,z$ plane is $(u_y, u_z)$; we want to rotate this projected vector to the vector $\left(0, \sqrt{u_y^2 + u_z^2}\right),$ which has the same length but whose direction is the positive $z$ direction.
You can find the angle that the vector $(u_y, u_z)$ makes with the $z$ axis in the $y,z$ plane using the formula $$ \alpha = \newcommand{\atan}{\mathrm{atan2}} \atan(u_y, u_z). $$
I am assuming here that you have the usual implementation of $\atan,$ in which $\atan(y,x)$ gives you the angle of the vector $(x,y)$ in the $x,y$ plane measured in the counterclockwise direction from the $x$ axis. But because we are doing $\atan(u_y, u_z)$ instead of $\atan(u_y, u_x),$ if you have the usual right-handed set of $x,y,z$ axes, and if you are looking onto the $y,z$ plane from the positive $x$ axis, the angle $\alpha$ is measured in a clockwise direction starting from the positive $z$ axis.
Note that the range of output of the $\atan$ function in most software implementations is either $[-\pi,\pi)$ or $(-pi,\pi].$ If $u_y > 0$ this will result in a positive angle; if $u_y < 0$ it will result in a negative angle. If $u_z > 0$ the magnitude of the angle will be less than $\pi/2,$ but if $u_x < 0$ the magnitude of the angle will be greater than $\pi/2.$ In short, no matter which way your original vector is pointing, $\atan(u_y, u_z)$ will tell you exactly how much it is rotated away from the positive $z$ direction (even if that is an obtuse angle) and in which direction, and it will identify exactly which of the four quadrants in the $y,z$ plane the vector points toward. This makes $\atan$ much more convenient than function such as $\mathrm{asin}$ or even the one-parameter $\mathrm{atan}$ function, which can only give you angles in two quadrants and therfore (in general) give you the wrong direction whenever the correct direction was in one of the other two quadrants.
If the $M_X$ parameter of your rotation function represents the conventional right-handed rotation around the $x$ axis, then $\alpha$ is exactly the rotation angle you need in order to rotate $u$ parallel to the $x,z$ plane. But you can set up a test case with an arbitrary $u$ (for example $u = (1,2,3)$) and try both rotation directions ($\alpha$ and $-\alpha$) to see which one zeros out the $y$ coordinate of the result in your software.
The result of this first rotation, viewed as a vector parallel to the $x,z$ plane, has coordinates $\left(u_x, \sqrt{u_y^2 + u_z^2}\right).$ So it makes an angle $$ \beta = \atan\left(u_x, \sqrt{u_y^2 + u_z^2} \right) $$ with the positive $z$ axis. If you are looking at the $x,z$ plane from the positive $y$ axis, the angle $\beta$ is measured counterclockwise from the positive $z$ axis, so the necessary rotation around the $y$ axis to bring the vector parallel to the $z$ axis is $-\beta$; but you can try both $-\beta$ and $\beta$ with a test vector in your software to find out which one is correct.
So the sequence of axis rotations, depending on exactly how your software interprets the axes and rotation angles, is:
$\alpha$ (or possibly $-\alpha$) around the $x$ axis;
$-\beta$ (or possibly $\beta$) around the $y$ axis.
You can then do any rotation you like (or a zero rotation) around the $z$ axis without any effect on the correctness of the result; but rotation around the $z$ axis will move both the $\startp'$ and $\endp'$ points to any direction from the $z$ axis you want. (That is, you can't change the $z$ coordinates, but you can take the $x$ and $y$ coordinates anywhere along a circle around the $z$ axis.)
There are so many questions about rotations of vectors already on this site, I was surprised when I failed to find one that is really asking just the same exact question.
There are some questions and answers that assume you already have a vector parallel to the desired axis of rotation. And you will get such a vector if you compute the cross product $v_1 \times v_2$, but I will show an alternative method that does not require a known rotation axis and works in any number of dimensions, not just 3D.
The trick is to express $v_2$ as a sum of two orthogonal unit vectors $e_1$ and $e_2$ in the same plane as $v_1$ and $v_2.$ While $v_1$ and $v_2$ are a basis for the vector subspace (the plane) within which you want to rotate $v_1,$ the vectors $e_1$ and $e_2$ are an orthonormal basis for that plane. We will construct this orthonormal basis so that $e_1$ points in the same direction as $v_1.$ Finding these vectors will mean that we would be able to write $$ v_2 = c_1 e_1 + c_2 e_2 $$ where $c_1$ and $c_2$ are some scalar values. It will be convenient to choose the orthonormal basis in such a way that $c_2$ is positive.
First we set $e_1$ to the unit vector in the same direction as $v_1$:
$$ e_1 = \frac{1}{\lVert v_1\rVert} v_1. $$
Now it's simple to find $c_1$ using the dot product:
$$ c_1 = v_2 \cdot e_1. $$
Let $u_2 = c_2 e_2$; then
$$ u_2 = c_2 e_2 = v_2 - c_1 e_1 = v_2 - (v_2 \cdot e_1) e_1. $$
Set $c_2$ to the length of $u_2$, that is, $ c_2 = \lVert u_2\rVert$; this guarantees that $c_2$ is positive. Then
$$ e_2 = \frac{1}{c_2} u_2 = \frac{1}{\lVert u_2\rVert}u_2. $$
This is essentially just the Gram-Schmidt process applied to the basis $v_1, v_2.$
Having done all this, it turns out that \begin{align} c_1 &= \lVert v_2\rVert \cos \theta,\\ c_2 &= \lVert v_2\rVert\sin \theta, \end{align} that is,
$$ v_2 = (\lVert v_2\rVert\cos\theta) e_1 + (\lVert v_2\rVert\sin\theta) e_2. $$
To rotate $v_1$ through an angle of exactly $\theta$ so that it points in exactly the same direction as $v_2$, compute
$$ (\lVert v_1\rVert\cos\theta) e_1 + (\lVert v_1\rVert\sin\theta) e_2. $$
That's a vector just like $v_2$ except that its length is $\lVert v_1\rVert$ instead of $\lVert v_2\rVert$ -- just compare the formulas.
To rotate $v_1$ toward $v_2$ by some other angle $\phi$, just compute
$$ \mathop{\mathrm{rot}_\phi} v_1 = (\lVert v_1\rVert\cos\phi) e_1 + (\lVert v_1\rVert\sin\phi) e_2. $$
Be careful when doing these operations that you are really working with 3D vectors in the usual mathematical sense; they represent only a direction and length, not specific starting and ending points. I add this warning to the answer because the first diagram illustrating the problem appears to show a basis or set of axes for your 3D coordinates, while the vectors are drawn as if they originated from a point other than the origin of the coordinates. Since the vectors in 3D space should be completely described by just three coordinates, it should be possible to simplify the figure by placing the intersection of the axes, the tails of vectors $v_1$ and $v_2,$ and the center of the circle all at the exact same point.
If the reason for drawing the figure as you did is because you are actually trying to find coordinates along a circle in 3D space with a center that is not at the origin, you'll want to find a vector $v_c$ from the origin to the center of the circle and then add $v_1'$ (the rotated $v_1$) to the vector $v_c$. The coordinates of $v_c + v_1'$ will be coordinates of a point on the circle.
Best Answer
Define the unit vectors along $a$ and $b$ as $u_1 = \dfrac{a}{|a|} $ and $u_2 = \dfrac{b}{|b|} $.
First compute the angle between $a,b$ as $\phi = \cos^{-1} u_1 \cdot u_2 $
Then after rotating vector $a$ , the final angle between $a$ and $b$ is given by
$\psi = \max \{ 0, \phi - \theta_\text{MAX} \} $
This way, if $\theta_\text{MAX} $ is greater than $\phi $ then $\psi $ will be zero.
Now we need to express the final rotated vector $a'$ in terms of $u_1$ and $u_2$
A unit vector lying in the plane of $u_1$ and $u_2$ and perpendicular to $u_2$ is given by
$ u_3 = \left( \dfrac{u_2 \times u_1}{|u_2 \times u_1|} \right) \times u_2 $
Where $\times$ denotes cross product. Finally, the rotated vector $a'$ is
$ a' =|a| \left( (\cos \psi) u_2 + (\sin \psi) u_3 \right) $