PaulHax / spin-controls

Arcball style controls for three.js Object3Ds and Cameras. Featuring pointer to trackball accuracy and unlimited rotation.
https://paulhax.github.io/spin-controls/
MIT License
78 stars 12 forks source link

Spin Controls used with Auto Rotation #23

Closed NicolasPerl closed 2 years ago

NicolasPerl commented 2 years ago

Hi There,

First off, thanks so much for working on this! It works great and has been a huge help.

Question... I have a mesh that has Spin Controls attached to it as well as an auto-rotate function that rotates the mesh on its Y-axis as seen below:

useFrame(() => { mesh.rotation.y = clock.getElapsedTime() /10; })

When the user clicks to spin the mesh the auto rotation is stopped to avoid jerking the mesh. The tricky part is having the auto-rotate pick up at the rotation.y that the user left the mesh after spinning it.

In other words - the expected behavior is after the user is done spinning the mesh the auto-rotate starts where the mesh finished rotation.

Has anyone found a good way of combining an autorotation with spin controls? Using the Three.js Clock isn't optimal because it can't be reset.

PaulHax commented 2 years ago

Heyo, thank you for the kind words. Looks like you got a neat project going there.

Let us add to the existing rotation. mesh.rotation.y += clock.getElapsedTime() /10

That will rotate relatively about the object local Y euler value, or something. Guessing you want to keep spinning around world Y axis. Multiplying quaternion adds their rotations. To rotate in an object's parent space, likely the world, quat.premultiply

The crux:

const axis = new THREE.Vector3(0, 1, 0)
const quat = new THREE.Quaternion()

useFrame((state, deltaTime) => {
  quat.setFromAxisAngle(axis, deltaTime * SPEED)
  ref.current.quaternion.premultiply(quat)
})

A complete example: https://codesandbox.io/s/basic-demo-forked-x785p?file=/src/App.js

NicolasPerl commented 2 years ago

Hey Paul,

Thanks for getting back to me! This worked flawlessly.

I need to get a better grasp on quaternions... they're pretty intimidating!

Feel free to share any resources you studied to help you grasp quaternions.

PaulHax commented 2 years ago

I don't understand quaternions =) But there are a few algebraic operations and their "geometric interpretation" (aka my mythical heuristics) that seems to cover many needs (with similar parallels to 4x4 matrix operations):

Multiplying quaternions adds one rotation to another. Order of rotations matter, hence quaternion.premultiply(quat) and quaternion.[post]multiply(quat). Usepremultiply to rotate in an objects parent coordinate system.
target = current * offset or often in 3D graphics world = parent * child

A quaternion's conjugate is the rotation in the other direction. So quatA * quatA.conjugate() = 0 rotation or something.

To find the rotation from one quaternion to another, the rotation offset: target = current * offset solve for offset by multiplying both sides by current.conjugate current.conjugate * target = current.conjugate * current * offset current's and its conjugate cancel each other and we have current.conjugate * target = offset

And in three.js

offset.copy(current.conjugate())
offset.multiply(target)

For setting the world orientation of a object deep in the scene graph hierarchy, can extract the quaternion from the parent's world matrix and apply the above where "current" is the parent world quaternion.

parent.getWorldQuaternion( parentToTargetOffset ).conjugate()
parentToTargetOffset.multiply( targetQuatWorldSpace )
child.quaternion.copy( parentToTargetOffset )