在Three.js中,我想让相机观察场景中的一个物体,当我点击另一个物体时,让相机平稳地旋转以查看新物体。 (即为相机的旋转设置动画)。
我已经检查了SO,这是最相似的问题:
Three.js How to use quaternion to rotate camera
我也尝试修改此website中的代码,我设法得到这样的内容http://jsfiddle.net/F7Bh3/
var quat0 = mesh2.quaternion;
var eye = mesh2.position;
var center = mesh.position;
var mat = new THREE.Matrix4();
mat.lookAt(center, eye, new THREE.Vector3(0,1,0));
var quat1 = new THREE.Quaternion();
quat1.setFromRotationMatrix( mat );
var qm = new THREE.Quaternion();
deltaTheta = angleBetweenQuats(quat0,quat1);
var frac = 0.2/deltaTheta;
if (frac>1) frac=1;
mesh2.quaternion.slerp(quat1,frac);
mesh2.quaternion.normalize();
但是当我尝试旋转相机而不是物体时,我得到的是:http://jsfiddle.net/5Peq9/1/
我错过了什么?提前致谢
答案 0 :(得分:8)
我设法使用四元数在three.js中平滑地为相机制作动画。我花了一段时间来弄清楚它,但是一旦完成它,观察四元数的运作情况是多么美妙。
方法是:
以及代码关键部分的快速示例:
var camera // camera
var cameraPos0 // initial camera position
var cameraUp0 // initial camera up
var cameraZoom // camera zoom
var iniQ // initial quaternion
var endQ // target quaternion
var curQ // temp quaternion during slerp
var vec3 // generic vector object
var tweenValue // tweenable value
// init camera
function setup()
{
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 2000)
camera.position = new THREE.Vector3(0, 0, 80)
cameraPos0 = camera.position.clone()
cameraUp0 = camera.up.clone()
cameraZoom = camera.position.z
}
// set a new target for the camera
function moveCamera(euler, zoom)
{
// reset everything
endQ = new THREE.Quaternion()
iniQ = new THREE.Quaternion().copy(camera.quaternion)
curQ = new THREE.Quaternion()
vec3 = new THREE.Vector3()
tweenValue = 0
endQ.setFromEuler(euler)
TweenLite.to(this, 5, { tweenValue:1, cameraZoom:zoom, onUpdate:onSlerpUpdate })
}
// on every update of the tween
function onSlerpUpdate()
{
// interpolate quaternions with the current tween value
THREE.Quaternion.slerp(iniQ, endQ, curQ, tweenObj.value)
// apply new quaternion to camera position
vec3.x = cameraPos0.x
vec3.y = cameraPos0.y
vec3.z = cameraZoom
vec3.applyQuaternion(curQ)
camera.position.copy(vec3)
// apply new quaternion to camera up
vec3 = cameraUp0.clone()
vec3.applyQuaternion(curQ)
camera.up.copy(vec3)
}
最后一步是找到要传递给moveCamera
的目标Euler旋转。在我的情况下,我使用TrackballControls找到一些有趣的相机位置/旋转,然后用euler = camera.rotation.clone()
检索它们并将其作为目标传递。例如:
moveCamera(new THREE.Euler(2.20, -0.15, 0.55), 120)
此处可以看到此方法的应用:http://brunoimbrizi.com/experiments/#/08
答案 1 :(得分:3)
对于那些使用Tween.js库的人:我改编了imbrizi的例子来旋转一组对象。同样可以应用于相机。
function tweenRotation(targetQuaternion, duration){
//tweens between zero and 1 values along Quaternion's SLERP method (http://threejs.org/docs/#Reference/Math/Quaternion)
qm = new THREE.Quaternion(); //initiate an empty Qt to be filled by the .slerp function
curQuaternion = group.quaternion; //the starting point of your rotation
var tween = new TWEEN.Tween({t:0}).to({t:1}, duration)
.easing( TWEEN.Easing.Quadratic.InOut )
.onUpdate(function(){
THREE.Quaternion.slerp(curQuaternion, targetQuaternion, qm, this.t);
qm.normalize();
group.rotation.setFromQuaternion(qm);
});
tween.start();
}
我最初使用Tween.js在原始矢量和目标矢量之间进行补间,并使用group.lookat(vector)函数在每一步将对象指向补间向量。但我发现它会产生不稳定,不一致的结果,特别是当原始和目标向量接近反平行时。这种方法,使用球面线性插值(slerp)给了我更平滑的结果。
答案 2 :(得分:1)
根据先前的答案和我制定的解决方案的文档,这似乎更干净一些。
const targetOrientation = new THREE.Quaternion().set(0, 0, 0, 1).normalize();
gsap.to({}, {
duration: 2,
onUpdate: function() {
camera.quaternion.slerp(targetOrientation, this.progress());
}
});
答案 3 :(得分:0)
相机有自己的LookAt方法。我怀疑这是因为相机的lookAt逻辑与两个3d对象的逻辑略有不同,因为相机的运动会反过来影响渲染视图(向右移动相机,并且场景似乎向左移动),因此需要反向思考或者隐藏反逻辑的特定方法。
我建议你试试相机的外观。