LERP for rotation, not positon?

I use the lerp() function to smoothly move objects in my ThreeJS virtual world. Works great. But how do I do the same for rotation? My virtual world gets updates from my server on where other players in the world currently are in the world. Then I LERP the player over to the new position. But I also want to change their rotation smoothly too.

So, if last update the user’s rotation was pointing straight ahead in the negative Z direction, and this update they turned 90 degrees, I want to smoothly change over to that new rotation instead of “jerking” the world object that is their avatar to the new rotation. I am hoping I don’t have to user “tween” or write my own code to do this. Is there a quick way to do this in ThreeJS?

You can set an axis around which to rotate - vec in the example, start/end values for the angle - a, amx in the example and then set quaternion from those two to rotate the mesh, I used linear increment ( well, lerp) and swap directions to make it loop
a += dir * 0.02;

So I take it by your reply there is no built-in function in ThreeJS to do this and that you have to roll your own, which you have gave an example of? I don’t want to loop because this my browser client “duplicating” the rotation that occurred on the source player’s PC. I just want to change from the current remote player’s rotation to the one reported in he new update in a smooth manner and then stop, once the target rotation is reached.

I added the loop, so you don’t have to reload the page to see the lerp again, you don’t have to do that of course.
The formula for any lerp is:

current_value = start_value + (end_value - start_value) * a,
a goes from 0 to 1, that’s you “built-in” function, not so hard to use this line of code to lerp w/e you want.

THREE stores rotation in quaternions, so you can lerp their angle or direction vector components - built-in lerp function is for vectors, so you can use it there, lerp for quaternions is not what you need judging by your question.

1 Like

Try Quaternion#slerp – three.js docs (threejs.org)

I use it to rotate the vehicle turrets, plus many other things, in this multiplayer example. fcs.sbcode.net
Source : First-Car-Shooter/car.ts (line 601)

2 Likes

lerp looks quite bad anyway, i think you would enjoy this: maath/packages/maath at main · pmndrs/maath · GitHub it has ootb support for all of threes primitives, including euler (dampE). you also don’t have to create throw-away variables no more.

import { damp, damp2, damp3, damp4, dampE, dampM, dampQ, dampS, dampC } from 'maath/easing'

function frameloop() {
  const delta = clock.getDelta()
  // Animates foo.bar to 10
  damp(foo, "bar", 10, 0.25, delta)

  // Animates mesh.position to 0,1,2
  damp3(mesh.position, [0, 1, 2], 0.25, delta)
  // Also takes vectors, shallow vectors and scalars
  // damp3(mesh.position, new THREE.Vector3(0, 1, 2), 0.25, delta)
  // damp3(mesh.position, { x: 0, y: 1, z: 2 }, 0.25, delta)
  // damp3(mesh.scale, 2, 0.25, delta)

  dampC(mesh.material.color, "green", 0.25, delta)
  // Also takes colors, fake colors, numbers and arrays
  // dampC(mesh.material.color, new THREE.Color("green"), 0.25, delta)
  // dampC(mesh.material.color, 0xdead00, 0.25, delta)
  // dampC(mesh.material.color, [1, 0, 0], 0.25, delta)
  // dampC(mesh.material.color, { r: 1, g: 0, b: 0 }, 0.25, delta)

  dampE(mesh.rotation, [Math.PI / 2, 0, 0], 0.25, delta)
  // Also takes eulers
  // dampE(mesh.rotation, new THREE.Euler(Math.PI / 2, 0, 0), 0.25, delta)

  // damp2 for Vector2
  // damp4 for Vector4
  // dampM for Matrix4
  // dampQ for Quaternion
  // dampS for Spherical

small demo:

1 Like

Thank you for the library link!

How so? I am now worried that I am not seeing something others more skilled than I can see. What are the main aesthetic flaws of lerp?

it looks quite jerky and clumsy compared to eased damp. the damp functions above are the same that are being used in unity, they look smooth and interpolate abrupt changes with momentum and velocity bounce-back.

You can check this topic for simple higher order transitions than lerp:

https://discourse.threejs.org/t/how-to-use-easing-functions-to-improve-lerp-slerp

and this is a comparison test:

Hello, I’ve had a lot of trouble with lerp/slerp on a carousel using tween. Here’s what I’ve come to recently.

The carousel positions it’s children items by it’s quantities and save the angle positions in a global var object.:

function setCarousel(){
	let radius = 4;
	let angle = Math.PI/180 * 360/carousel.children.length;
	for(let i = 0; i < carousel.children.length; i++){
		carousel.children[i].position.x = radius * Math.sin(angle*i);
		carousel.children[i].position.z = radius * Math.cos(angle*i);
		carouselItems[carousel.children[i].name] = angle*i;
	}
	scene.add(carousel);				
}

At the tween animation I wanted the clicked child to face the camera. So I createad a var (itemRotationPos) that is subtracted by the full loop (360 deg in rad 6.2819), and a var for the differential from current value and the Front postioned var (itemRotationDelta). After that on complete function I’ve re assign the final value as at the item’s gloval var value:

let itemRotationPos = 6.2819 - carouselItems[item.name];
let itemRotationDelta = itemRotationPos;
if(Math.abs(carousel.rotation.y - itemRotationPos) > 3.14){
	if(carousel.rotation.y > itemRotationPos){
		itemRotationDelta += 6.2819;
	}else{
		carousel.rotation.y += 6.2819;
	}
}

let centerCarousel = new TWEEN.Tween(carousel.rotation).to({y: itemRotationDelta}, 1000).easing(TWEEN.Easing.Quadratic.Out).onComplete( () => {
	carousel.rotation.y = itemRotationPos;
}).start();

The rotate carousel function thats called at by animater if a var “moving” is true:

function rotateCarousel(){
	if(carousel.rotation.y > 6.2819){
		carousel.rotation.y = 0;
	}
	if(carousel.rotation.y < 0){
		carousel.rotation.y = 6.2819;
	}
	carousel.rotation.y -= camera.position.x/500 + 0.003;
}

Cheers