如何让 GSAP 找到 "most optimal" 旋转方法?
How do I make GSAP find the "most optimal" rotation method?
我希望我的网格在所有方向上以 90 度角旋转,但让 GSAP 找到最“最佳旋转”。
所以如果我按 1
它会在
this.meshName.rotation.y = 0
和2
this.meshName.rotation.y = Math.PI/2
和3
this.meshName.rotation.y = Math.PI
和4
this.meshName.rotation.y = (3*Math.PI)/2
GSAP 没有找到“最优旋转”,
例如,如果我按4
,然后按1
,它会像这样旋转(红色)
我希望它像这样旋转(绿色)
\
我能想到的唯一解决方案是,如果最后按下的键是 4
(然后我按下 1
),则制作 this.meshName.rotation.y = 2*Math.PI
,但我必须将其设置回去在动画之后到 0
否则它会影响其他键。我现在所拥有的只是有时有效,但它真的很乱。我觉得有更好的方法来做到这一点。:
this.testLastKey = false;
document.addEventListener('keydown', function(event) {
if(event.key === "1") {
if(this.testLastKey){
GSAP.to(this.mesh.rotation, {
y: Math.PI*2,
duration: 0.2,
});
this.mesh.rotation = 0
} else {
GSAP.to(this.mesh.rotation, {
y: 0,
duration: 0.2,
});
}
this.testLastKey = false
}
else if(event.key === "2") {
GSAP.to(this.mesh.rotation, {
y: Math.PI / 2,
duration: 0.2,
});
this.testLastKey = false
}
else if(event.key === "3") {
GSAP.to(this.mesh.rotation, {
y: Math.PI,
duration: 0.2,
});
this.testLastKey = false
}
else if(event.key === "4") {
GSAP.to(this.mesh.rotation, {
y: (3*Math.PI)/2,
duration: 0.2,
});
this.testLastKey = true
}
}
所以这里的主要问题是常规(欧拉)旋转角度在必须过零时不能很好地插值。
四元数来拯救!
我知道,我知道,四元数很难理解。但不用担心,只需调用四元数辅助方法来完成繁重的工作:-)。一旦将所有角度转换为四元数,它们的插值就会非常好。
第二个问题是GSAP不知道四元数值代表角度,所以插值真的很奇怪。它完成了工作,但动作看起来真的很奇怪。最好只使用 3D 库的四元数插值方法(连同 GSAP)。本例使用球面线性插值(slerp)
(ThreeJS 实现)
//OBJECTIVE
//User presses keys 1,2,3 or 4 which should rotate model's mesh to face 0,90,
//180 or 270 degrees respectively (rotating on the y-axis)
document.addEventListener("keypress", (event) => {
//Taking advantage of integer keypress to simplify all rotation cases
// into 1 case. For other cases like alphabet key presses you can create
// a map of some sort
const inKey = parseInt(event.key) - 1; //convert input key to 0 indexed 'iterator'
const step = { factor: 0 }; //GSAP needs value set up as a property/object
//prevent smart people from breaking your app with alphabet iterators :-)
if (Number.isNaN(inKey)) return;
//Create quaternion objects to store mesh's initial & final/target rotation.
//Here, setFromEuler(x,y,z) converts a regular <x,y,z> rotation vector to
// a quaternion <x,y,z,w>
const initRot = new THREE.Quaternion().copy(mesh.quaternion);
const targetRot = new THREE.Quaternion().setFromEuler(
//Destination y-axis angle uses integer keypress input like an 'iterator'
// current value, to make an implicit "map" for this exact use case/keypress.
// Effectively 1=>0°,2=>90°,3=>180°,4=>270°,other input numbers modulo 4
new THREE.Euler(0, (inKey * Math.PI) / 2, 0)
);
//GSAP tweening a number 'step.factor' from 0 to 1
GSAP.to(step, {
factor: 1, //use this factor to interpolate "manually"
duration: 0.2,
//Fake "render loop" :-) Interpolate using threeJS slerpQuaternion
// since GSAP doesn't know its an angle and interpolates awkwardly :-(.
// This way we can run a custom interpolate on tick
onUpdate: () =>
mesh.quaternion.slerpQuaternions(initRot, targetRot, step.factor),
}); //end of GSAP.to
}); //end of addEventListener
长话短说;博士。以下是如何在按键时旋转 3D 对象“网格”。 (相同但无评论)
document.addEventListener("keypress", (event) => {
const inKey = parseInt(event.key) - 1;
const step = { factor: 0 };
if (Number.isNaN(inKey)) return;
const initRot = new THREE.Quaternion().copy(mesh.quaternion);
const targetRot = new THREE.Quaternion().setFromEuler(
new THREE.Euler(0, (inKey * Math.PI) / 2, 0)
);
GSAP.to(step, {
factor: 1,
duration: 0.2,
onUpdate: () =>
mesh.quaternion.slerpQuaternions(initRot, targetRot, step.factor),
});
});
我希望我的网格在所有方向上以 90 度角旋转,但让 GSAP 找到最“最佳旋转”。
所以如果我按 1
它会在
this.meshName.rotation.y = 0
和2
this.meshName.rotation.y = Math.PI/2
和3
this.meshName.rotation.y = Math.PI
和4
this.meshName.rotation.y = (3*Math.PI)/2
GSAP 没有找到“最优旋转”,
例如,如果我按4
,然后按1
,它会像这样旋转(红色)
我希望它像这样旋转(绿色)
我能想到的唯一解决方案是,如果最后按下的键是 4
(然后我按下 1
),则制作 this.meshName.rotation.y = 2*Math.PI
,但我必须将其设置回去在动画之后到 0
否则它会影响其他键。我现在所拥有的只是有时有效,但它真的很乱。我觉得有更好的方法来做到这一点。:
this.testLastKey = false;
document.addEventListener('keydown', function(event) {
if(event.key === "1") {
if(this.testLastKey){
GSAP.to(this.mesh.rotation, {
y: Math.PI*2,
duration: 0.2,
});
this.mesh.rotation = 0
} else {
GSAP.to(this.mesh.rotation, {
y: 0,
duration: 0.2,
});
}
this.testLastKey = false
}
else if(event.key === "2") {
GSAP.to(this.mesh.rotation, {
y: Math.PI / 2,
duration: 0.2,
});
this.testLastKey = false
}
else if(event.key === "3") {
GSAP.to(this.mesh.rotation, {
y: Math.PI,
duration: 0.2,
});
this.testLastKey = false
}
else if(event.key === "4") {
GSAP.to(this.mesh.rotation, {
y: (3*Math.PI)/2,
duration: 0.2,
});
this.testLastKey = true
}
}
所以这里的主要问题是常规(欧拉)旋转角度在必须过零时不能很好地插值。
四元数来拯救!
我知道,我知道,四元数很难理解。但不用担心,只需调用四元数辅助方法来完成繁重的工作:-)。一旦将所有角度转换为四元数,它们的插值就会非常好。
第二个问题是GSAP不知道四元数值代表角度,所以插值真的很奇怪。它完成了工作,但动作看起来真的很奇怪。最好只使用 3D 库的四元数插值方法(连同 GSAP)。本例使用球面线性插值(slerp)
(ThreeJS 实现)
//OBJECTIVE
//User presses keys 1,2,3 or 4 which should rotate model's mesh to face 0,90,
//180 or 270 degrees respectively (rotating on the y-axis)
document.addEventListener("keypress", (event) => {
//Taking advantage of integer keypress to simplify all rotation cases
// into 1 case. For other cases like alphabet key presses you can create
// a map of some sort
const inKey = parseInt(event.key) - 1; //convert input key to 0 indexed 'iterator'
const step = { factor: 0 }; //GSAP needs value set up as a property/object
//prevent smart people from breaking your app with alphabet iterators :-)
if (Number.isNaN(inKey)) return;
//Create quaternion objects to store mesh's initial & final/target rotation.
//Here, setFromEuler(x,y,z) converts a regular <x,y,z> rotation vector to
// a quaternion <x,y,z,w>
const initRot = new THREE.Quaternion().copy(mesh.quaternion);
const targetRot = new THREE.Quaternion().setFromEuler(
//Destination y-axis angle uses integer keypress input like an 'iterator'
// current value, to make an implicit "map" for this exact use case/keypress.
// Effectively 1=>0°,2=>90°,3=>180°,4=>270°,other input numbers modulo 4
new THREE.Euler(0, (inKey * Math.PI) / 2, 0)
);
//GSAP tweening a number 'step.factor' from 0 to 1
GSAP.to(step, {
factor: 1, //use this factor to interpolate "manually"
duration: 0.2,
//Fake "render loop" :-) Interpolate using threeJS slerpQuaternion
// since GSAP doesn't know its an angle and interpolates awkwardly :-(.
// This way we can run a custom interpolate on tick
onUpdate: () =>
mesh.quaternion.slerpQuaternions(initRot, targetRot, step.factor),
}); //end of GSAP.to
}); //end of addEventListener
长话短说;博士。以下是如何在按键时旋转 3D 对象“网格”。 (相同但无评论)
document.addEventListener("keypress", (event) => {
const inKey = parseInt(event.key) - 1;
const step = { factor: 0 };
if (Number.isNaN(inKey)) return;
const initRot = new THREE.Quaternion().copy(mesh.quaternion);
const targetRot = new THREE.Quaternion().setFromEuler(
new THREE.Euler(0, (inKey * Math.PI) / 2, 0)
);
GSAP.to(step, {
factor: 1,
duration: 0.2,
onUpdate: () =>
mesh.quaternion.slerpQuaternions(initRot, targetRot, step.factor),
});
});