Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
321dev

Tweening three.js quaternions

Recommended Posts

There are quite a few posts about this, but they're many years old, and many of them mention a plugin that can handle quaternions. What's the state today? Can GSAP tween quaternions, or do we still need a plugin?

 

Specifically, i'd like to use interpolate() with three.js quaternions.

 

(I know about three.js quaternion.slerp, but i need to interpolate over a dynamic number of values.)

Link to post
Share on other sites
14 minutes ago, Cassie said:

I did a bit of googling and stumbled on this thread on the three.js discourse site - does this help at all?

Thanks for your response, but unfortunately that does not help.

 

Interpolating any linear values (like a 3D position) with GSAP is not a problem, but Quaternions can't be interpolated that way. The interpolating code must be aware of the meaning of the values. E.g. when you wanted to interpolate a rotation in degrees from 350 to 10, the code should go from 350...359..0...10, instead of going backwards from 350 to 10.

 

 

 

  • Like 1
Link to post
Share on other sites

Ah, I see. I'm afraid I'm not going to be able to help here. 

Maybe @OSUblake or @Rodrigo will be able to help?

Link to post
Share on other sites
7 minutes ago, 321dev said:

E.g. when you wanted to interpolate a rotation in degrees from 350 to 10, the code should go from 350...359..0...10, instead of going backwards from 350 to 10.

This seems like it could be a good use case for gsap's modifiers. Like @Cassie I'm not super familiar with what you are trying to do... can you set up a basic CodePen of what GSAP should/could be tweening?

https://greensock.com/docs/v3/GSAP/CorePlugins/ModifiersPlugin

  • Like 3
Link to post
Share on other sites

Yeah, I'd love to see. I'm really fascinated by this. It sounds like crazy sci-fi tweening.

Link to post
Share on other sites

The modifiers might work, if i knew how to interpolate quaternions at low level - which i don't.

 

For now, i'll try to use "normal" Euler rotations like i found here: 

See the Pen GRooLza by ste-vg (@ste-vg) on CodePen

and see how it goes.


Thanks for your help.

  • Like 1
Link to post
Share on other sites
8 hours ago, 321dev said:

There are quite a few posts about this, but they're many years old, and many of them mention a plugin that can handle quaternions. What's the state today? Can GSAP tween quaternions, or do we still need a plugin?

 

That's from the flash days.

 

You should be able to just use onUpdate kind of like what shown here... although they are using Tween.js

 

https://discourse.threejs.org/t/animating-quaternion-rotation/8015/12

 

 

  • Like 1
Link to post
Share on other sites
2 hours ago, 321dev said:

E.g. when you wanted to interpolate a rotation in degrees from 350 to 10, the code should go from 350...359..0...10, instead of going backwards from 350 to 10.

 

@GreenSock do you have some code for this? I can't find my demos that show this.

 

  • Like 1
Link to post
Share on other sites
10 minutes ago, OSUblake said:

 

@GreenSock do you have some code for this? I can't find my demos that show this.

 

That was just an example showing why the "normal" interpolation doesn't work with angles. I don't have code for this.

Link to post
Share on other sites

I know, that's why I tagged someone else 😉

Link to post
Share on other sites
19 minutes ago, OSUblake said:

You should be able to just use onUpdate kind of like what shown here... although they are using Tween.js

https://discourse.threejs.org/t/animating-quaternion-rotation/8015/12

Yes, thanks. But as i mentioned in my OP, i know how to interpolate between two Quaternions using three.js method.

 

But i need to interpolate between more values, but i don't think just interpolating between 0 and 1, then 1 and 2, etc. will give a smooth result. But maybe i should try it out and check how bad it looks.

Link to post
Share on other sites

What properties are you trying to animate? Do you have some psuedo code?

  • Like 1
Link to post
Share on other sites
45 minutes ago, OSUblake said:

What properties are you trying to animate? Do you have some psuedo code?

In an ideal world, i 'd like to use gsap.utils.interpolate like this:

 

let q1 = new THREE.Quaternion()
q1.setFromEuler(new THREE.Euler( THREE.Math.degToRad(0), THREE.Math.degToRad(45), THREE.Math.degToRad(0), 'XYZ' ))

let q2 = new THREE.Quaternion()
q2.setFromEuler(new THREE.Euler( THREE.Math.degToRad(45), THREE.Math.degToRad(0), THREE.Math.degToRad(90), 'XYZ' ))

let q3 = new THREE.Quaternion()
q3.setFromEuler(new THREE.Euler( THREE.Math.degToRad(90), THREE.Math.degToRad(90), THREE.Math.degToRad(90), 'XYZ' ))


var interp = gsap.utils.interpolate([q1, q2, q3]);

let qx = interp(0.3)

 

Link to post
Share on other sites

So using three.js's slerp is fine, you just need to interpolate an array of them?

 

Would something like this work?

 

const interp = interpolate([q1, q2, q3]);

let qx = interp(0.3);

function interpolate(targets) {
  
  const interpolators = [];
  let len = targets.length;
  const iLen = len - 2;
  const q = new THREE.Quaternion();
  
  for (let i = 1; i < len; i++) {
    interpolators.push(slerp(targets[i - 1], targets[i], q));
  }
  
  len--;
    
  return p => {
    p *= len;
    let i = Math.min(iLen, ~~p);
    return interpolators[i](p - i);
  }
}

function slerp(a, b, q) {
  return p => {
    // three.js slerp 
    return q.slerpQuaternions(a, b, p);
  }
}

 

  • Like 1
Link to post
Share on other sites

So this would first interpolate between items 0 and 1, then 1 and 2, and so on. That's what i planed to do, but i wasn't sure if the transitions were smooth (enough). I'll try it out tomorrow.

 

BTW:  Maybe gsap.utils.interpolate() could be expanded so that you could pass a custom function that interpolates between two elements? 

 

Thanks a lot for your time and effort!

Link to post
Share on other sites
1 minute ago, 321dev said:

So this would first interpolate between items 0 and 1, then 1 and 2, and so on.

 

Yep.

 

2 minutes ago, 321dev said:

BTW:  Maybe gsap.utils.interpolate() could be expanded so that you could pass a custom function that interpolates between two elements? 

 

That's not a bad idea. Any thoughts on this @GreenSock?

 

Link to post
Share on other sites
4 minutes ago, 321dev said:

That's what i planed to do, but i wasn't sure if the transitions were smooth (enough).

 

If it's not smooth, maybe make a simple demo so we can mess around and tweak it.

 

Link to post
Share on other sites
2 hours ago, OSUblake said:

 

3 hours ago, 321dev said:

BTW:  Maybe gsap.utils.interpolate() could be expanded so that you could pass a custom function that interpolates between two elements? 

 

That's not a bad idea. Any thoughts on this @GreenSock?

An interpolator for an interpolator? I'm a little fuzzy on what exactly you mean here - got a sketch of an API and a sample use case? 

Link to post
Share on other sites
18 minutes ago, GreenSock said:

An interpolator for an interpolator? I'm a little fuzzy on what exactly you mean here - got a sketch of an API and a sample use case? 

The purpose is to enable gsap.utils.interpolate() to interpolate values it can't interpolate (correctly) otherwise, in my example a THREE.Quaternion

Link to post
Share on other sites
19 minutes ago, 321dev said:

The purpose is to enable gsap.utils.interpolate() to interpolate values it can't interpolate (correctly) otherwise, in my example a THREE.Quaternion

Ha ha - I figured that much. :) I'm asking about implementation details. What would this function look like exactly? How would it integrate with gsap.utils.interpolate()? Got pseudo code? 

Link to post
Share on other sites

Maybe like this?

 

const interp = interpolate([q1, q2, q3], (start, end, progress) => {
  // custom interpolation
  return ...;
});

 

Link to post
Share on other sites
On 5/5/2021 at 6:02 PM, OSUblake said:

Maybe like this?

 


const interp = interpolate([q1, q2, q3], (start, end, progress) => {
  // custom interpolation
  return ...;
});

 

Yeah, I'm not seeing a very clean way of fitting that in there. It'd take a lot of extra code to accommodate, and it would definitely muddy the API - it already has 4 different method signatures; this would literally double that. 

 

I think for a situation like this, a custom plugin or an effect would be a more intuitive option. Or just a straight-up helper function like you suggested earlier. 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×