Vector Rotation around a Line between two vectors

   2777   9   1
User Avatar
Member
17 posts
Joined: April 2017
Offline
Hi everyone,

I want to interpolate between 2 given random Vectors along a not straight line. I have tried lerp, slerp, quaternions and rotation Matrices and I cant get it to work.

I have a random curve and a starting Vector at point 0 and an ending Vector at point n. All I want is a vector that blends beetween the two vectors on the shortest path possible and set that vector as pointAttrib. Preferably with easing in/out, but thats not neccessary.

The pictures show something similar to what i want. the green vector are the start and end, and the blue is the interpolation. I need this to work for any kind of start an end vector.
Can some mercyful soul please help me to get this working in vex? I have beed trying for days now
I added my testfile in case somebody wants to take a look at my tries.

Regards Moon

Attachments:
Side.png (249.2 KB)
Top.png (222.4 KB)
VectorRotation.hipnc (230.9 KB)

User Avatar
Member
8786 posts
Joined: July 2007
Offline
you can use Orientation Along Curve SOP
and specify Target Up Vector as Custom or Attribute
check Use Target End Up Vector

then you can set your start and end vectors either in UI or using primitive attributes on the curve
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
17 posts
Joined: April 2017
Offline
Thanks for your help
I sadly cannot use a Node for that. I need to compute that multiple times inside a vex node because I create and delete points on the get go and calculate the rotation inbetween.

However, in theory your advice is doing exacly what i need. I only need this to work in vex.
User Avatar
Member
4703 posts
Joined: Feb. 2012
Offline
Hi,

Here is one way using quaternions that also take length of the vectors into account:



vector interpvectors ( vector v0; vector v1; float amount )
{
    vector4 q0 = quaternion ( normalize ( v0 ) );
    vector4 q1 = quaternion ( normalize ( v1 ) );
    vector4 q2 = slerp ( q0, q1, amount );
    vector vec = qconvert ( q2 );
    vec = normalize ( vec ) * lerp ( length ( v0 ), length ( v1 ), amount );
    
    return vec;
}

float s = float ( @ptnum ) / ( @numpt - 1 );

vector v0 = point ( 0, "N", 0 );
vector v1 = point ( 0, "N", @numpt - 1 );

@N = interpvectors ( v0, v1, s );

It assumes that the point numbers are ordered. If not, you can use some other value like curveu, etc.
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com]

youtube.com/@pragmaticvfx | patreon.com/animatrix | pragmaticvfx.gumroad.com
User Avatar
Member
17 posts
Joined: April 2017
Offline
Thanks for your reply animatrix_,

I have tried something similar a little bit earlier and sadly the Problem persist. I uploaded two pictures that show my problems with this approach. I need it to loop around the line even if the vectors are 1 and -1. While that works with matrices, those only loop around the line anticlockwise.

I additionally tried this code: *just feed a single Point in a Pointwrangle*
vector axis1 = normalize(set(1,0,0));
vector axis2 = normalize(set(-1,0,-0.5));
v@axis = axis1;
v@axis2 = axis2;

vector q1 = cross(set(0,1,0), axis1);
vector q2 = cross(set(0,1,0), axis2);

vector4 quat1 = quaternion(radians(90), q1);
vector4 quat2 = quaternion(radians(90), q2);

vector norm = set(0,1,0);//normalize(axis1 + axis2);
vector4 quat3 = slerp(quat1, quat2, chf("t"));
norm = qrotate(quat3, norm);

int pt1 = addpoint(0, set(0,0,0));
int pt2 = addpoint(0, norm);
int line = addprim(0, "polyline", pt1, pt2);

v@N = norm;

And this is super close to what i want, except that it is doing this weird upwards loop near the middle of the interpolation. Does anyone happen to know how to fix it or have an alternative version?

Best regards Moon

Attachments:
error.png (385.3 KB)
error2.png (319.9 KB)

User Avatar
Member
4703 posts
Joined: Feb. 2012
Offline
Yes that's expected behaviour.

When you try to slerp between two opposing vectors, you effectively ask Houdini to rotate 180 degrees around some arbitrary axis. The problem is the operation becomes undefined because there are infinitely many axes that you could rotate around to turn one vector into the other.

What you can do is to define a default axis of rotation to use in cases where the start and end vectors are either identical or opposite. For example you can use Y up or a normalized vector from the start to the end of your curve geometry.
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com]

youtube.com/@pragmaticvfx | patreon.com/animatrix | pragmaticvfx.gumroad.com
User Avatar
Member
17 posts
Joined: April 2017
Offline
I understand that rotating between two perfectly opposing vectors is a problem, yes. But why is the second error image, where they are not oppsing each other not a good slerp? For me it looks more like a regular lerp than a slerp where afterwards the vectors are normalized.

From my understanding a slerp along 6 points between 2 vectors that have a 100° difference should return 0° when the bias is 0, 100° when the bias is 1 and then 20°*i for each intermediate point. Am I just missunderstanding this function? Because that is not what is happening in my second error image from my previous post.

Also, how would I go about using a rotation vector for a quaternion? I didn't know that was possible.

Sorry for all the confusion. I really appreciate the time you take to answer <3
Best regards Moon
User Avatar
Member
4703 posts
Joined: Feb. 2012
Offline
The behaviour you're seeing is due to the way spherical linear interpolation works when interpolating between two vectors that are almost directly opposite each other. When vectors are nearly diametrically opposed, the direction of the interpolated vectors can change rapidly around the midpoint of the interpolation, causing them to closely resemble the starting vector, then rapidly switch to resemble the ending vector.

You can think of slerp as an interpolation that moves along the "shortest path" on the surface of a sphere between the start and end vectors. This path is called a "great circle". When your vectors are nearly opposites, the shortest path can be almost any direction along the sphere, and the precise direction can be influenced by very slight changes in the end vector or due to floating point precision errors.

This is why the interpolation looks uniform when visualized on a sphere as it's always moving along the shortest path, but can seem to favor one vector then suddenly switch to the other when visualized linearly.

If you want to have uniform interpolation between your vectors, here is one way to do it:



vector interpvectorsuniform ( vector v0; vector v1; float amount )
{
    matrix3 m = ident ( );
    
    float totalangle = acos ( dot ( normalize ( v0 ), normalize ( v1 ) ) );
    vector axis = normalize ( cross ( v0, v1 ) );
    rotate ( m, totalangle * amount, axis );
    
    return v0 * m;
}

float s = float ( @ptnum ) / ( @numpt - 1 );

vector v0 = { 1, 0, 0 };
vector v1 = { -1, 0, 0.01 };

@N = interpvectorsuniform ( v0, v1, s );

MoonwalkJunkie
Also, how would I go about using a rotation vector for a quaternion? I didn't know that was possible.

quaternion function supports that:
https://www.sidefx.com/docs/houdini/vex/functions/quaternion.html [www.sidefx.com]
Edited by animatrix_ - June 27, 2023 13:42:08
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com]

youtube.com/@pragmaticvfx | patreon.com/animatrix | pragmaticvfx.gumroad.com
User Avatar
Member
17 posts
Joined: April 2017
Offline
I had to normalize the dot product vectors, but now it is working perfectly! Thank you so much <3
User Avatar
Member
4703 posts
Joined: Feb. 2012
Offline
In Houdini 20, you can do the exact same thing using the new slerpv VEX function:
https://www.sidefx.com/docs/houdini/vex/functions/slerpv.html [www.sidefx.com]

float s = float ( @ptnum ) / ( @numpt - 1 );

vector v0 = { 1, 0, 0 };
vector v1 = { -1, 0, 0.01 };

@N = slerpv ( v0, v1, s );



Thanks to SESI for adding this function to built-in VEX functions based on my RFE on the H20 beta.
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com]

youtube.com/@pragmaticvfx | patreon.com/animatrix | pragmaticvfx.gumroad.com
  • Quick Links