# Decompose + TWEEN?

Is it possible to tween decompose instead of having to tween 3x vector3 for Pos, Rot, Scale? Or if not a way to tween between decompose is there a way to tween Pos, Rot, Scale at the same time? Ive tried but no success. Im running three tweens currently for the job. 1 per vector.

Are you using tween.js? Not clear what you’re asking.

Do you mean is it possible to tween a matrix? If so, then yes. You can tween the values in the matrix.elements array.

Thanks for the reply @looeee and @trusktr . I currently have an instancedMesh of elements that I tween. I tween their pos, rot, scale. But I do it with three different tweens. I would like to tween all three Vectors with one tween.

Something like:

new Tween( object.position, obj.rotation, obj.scale ).to( target.object.position, target.object.rotation, target.obj.scale )

Inside my tween I then convert the positions to a matrix and compose them and use the new composed matrix to update the matrix of the instances. So I know its obv possible to tween the matrices. I just want all three vectors in one tween.

@D13
Use .onUpdate() and lerp values for position, rotation and scale all at once there: Edit fiddle - JSFiddle - Code Playground

1 Like

@prisoner849 Boom! Thank you!

So, qq: I implemented this and indeed it works like a champ. A big tween performance enhancement. However, with this approach its similar to slerp. We turn 0 into 1 over series of steps. However, I need to preserve the current position of existing objects “panelCurrent.position”. It seems this solution starts at ‘val:0’ every time. Is there a way it could start at the current objects position?

So the big diff here is going from a starting vector assumed at ‘current.object.position’ vs a starting vector assumed from ‘0’.

for( let i = 0; i < obLen; i++ ) {

const panelCurrent = meshCache[ i ];
const panelTarget = targets.radial[ i ];
const panelMatrix = panelTarget.matrix;
const orientation = panelCurrent.quaternion();
const offset = new THREE.Vector3();
const newRot = new THREE.Euler();
let valsCount = { val: 0 }
let vals = {
pos: new THREE.Vector3(),
rot: new THREE.Vector3(),
sca: new THREE.Vector3()
}

new TWEEN.Tween( valsCount ).to({ val: 1 }, Math.random() * duration * 2 ).onUpdate( function(){

vals.pos.lerpVectors( panelCurrent.position, panelTarget.position, valsCount.val );
vals.rot.lerpVectors( panelCurrent.rotation, panelTarget.rotation, valsCount.val );
vals.sca.lerpVectors( panelCurrent.scale, panelCurrent.scale, valsCount.val );

newRot.set( vals.rot.x, vals.rot.y, vals.rot.z );
offset.set( vals.pos.x, vals.pos.y, vals.pos.z ).multiplyScalar( 0.075 );
orientation.setFromEuler( newRot );
panelMatrix.compose( offset, orientation, vals.sca );

currentMesh.setMatrix( i, panelMatrix );
currentMesh.instanceMatrix.needsUpdate = true;

}).start();

}

What I miss? I need my positions to start from ‘panelCurrent.position’. Thank you!

@D13
Use .onComplete() and save current values into initVals Edit fiddle - JSFiddle - Code Playground

PS Reading “User’s guide” time to time is helpful tween.js/user_guide.md at 8db070d25a82c19772352bbcbc33a326e6882b4e · tweenjs/tween.js · GitHub

1 Like

Thank You!

@D13 You’re welcome

@D13 Besides lerping like @prisoner849 suggested, you can also animate any number if properties of an object. The following is closer to what you were thinking:

new Tween({
position: object.position,
rotation: obj.rotation,
scale: obj.scale
}).to({
position: target.object.position,
rotation: target.object.rotation,
scale: target.obj.scale
})

then in onUpdate you can read the values and use them on each update:

onUpdate(theValues => {
console.log(theValues.position, theValues.rotation, theValues.scale)
})

where theValues is the same object you passed to new Tween, which gets modified on each update.

I’ve seen that, that you can change nested objects, but seems I did something wrong so it didin’t work

Ah! Made it working with nested objects: Edit fiddle - JSFiddle - Code Playground
Just had to care about box.rotation.order as it’s not a number, but a string, and it becomes NaN whilst tweening.

Very Nice, yes, I was able to use the onComplete solution just fine. I think as far as performance goes this is the best without going to a TWEEN Manager, which could be tuned to squeeze the last inth of performance when getting into those 10k+ instances. For now, I’m happy with performance as it is. When I get into the big data I’ll revisit this.

Solution for now:

new TWEEN.Tween({ val:0 }).to({ val: 1 }, Math.random() * duration * 2 )
.easing( TWEEN.Easing.Exponential.InOut )
.onUpdate( value => {

// lerp new positions
vals.pos.lerpVectors( panelCurrent.position, targets.radial[ i ].position, value.val );
vals.rot.lerpVectors( panelCurrent.rotation, targets.radial[ i ].rotation, value.val );
vals.sca.lerpVectors( panelCurrent.scale, targets.radial[ i ].scale, value.val );

// compose new matrix
newRot.set( vals.rot.x, vals.rot.y, vals.rot.z );
offset.set( vals.pos.x, vals.pos.y, vals.pos.z );
offset.multiplyScalar( 0.025 );
orientation.setFromEuler( newRot );
panelMatrix.compose( offset, orientation, vals.sca );

// update positions
currentMesh.setMatrixAt( i, panelMatrix );

currentMesh.instanceMatrix.needsUpdate = true;

}).onComplete(() => {

// reset positions
panelCurrent.position.set( vals.pos.x, vals.pos.y, vals.pos.z );
panelCurrent.rotation.set( vals.rot.x, vals.rot.y, vals.rot.z );
panelCurrent.scale.set( vals.sca.x, vals.sca.y, vals.sca.z );
offset.set( panelCurrent.position.x, panelCurrent.position.y, panelCurrent.position.z );
offset.multiplyScalar( 0.025 );
newRot.set( panelCurrent.rotation.x, panelCurrent.rotation.y, panelCurrent.rotation.z );
orientation.setFromEuler( newRot );
panelMatrix.compose( offset, orientation, panelCurrent.scale );

}).start();

Of course, there is the caveat that the “onComplete” has to finish its animation cycle to save the new position values. So, if a user clicks a new transition before the current one is finished then you get a snapping effect as the new positions are not saved and instead pull from the previous positions in the matrix. I can handle that though…

For now, this was plenty good enough. A million thanks!

Oh I see. Ok, yes, this is nice too. Not having to use onComplete to save the new positions. I was going to play with a version of this soon.