我在three.js场景中遇到FPS相机控件的问题。我正在使用Raycaster
来确定摄影机组的位置,基于它与沿Y轴的场景相交(如果您愿意,则为穷人的重力),然后应用用户输入来移动。摄像头组的位置会不断重置为每帧的相交位置,从本质上将您粘在该点上。
我假设这是一个updateMatrix()
问题,或者是某个地方Vector3
通过引用传递,但是对于我一生,我似乎无法全力以赴。我需要一些帮助...我希望这段代码很清楚,可以帮助您理解问题:
renderer.setAnimationLoop((event) => {
if (clock.running) {
update();
renderer.render(scene,character.view);
}
});
clock.start();
//
const update = () => {
// velocity
const velocity = new THREE.Vector3();
velocity.x = input.controller.direction.x;
velocity.z = input.controller.direction.y;
velocity.clampLength(0,1);
if (velocity.z < 0) {
velocity.z *= 1.4;
}
// gravity
if (scene.gravity.length() > 0) {
const origin = new THREE.Vector3().copy(character.view.position);
const direction = new THREE.Vector3().copy(scene.gravity).normalize();
const intersection = new THREE.Raycaster(origin,direction).intersectObjects(scene.collision).shift();
if (intersection) {
character.group.position.copy(intersection.point);
character.group.updateMatrix();
}
}
// rotation
const rotation = new THREE.Euler();
rotation.x = input.controller.rotation.y;
rotation.y = input.controller.rotation.x;
character.group.rotation.set(0,rotation.y,0);
character.view.rotation.set(rotation.x,0,0);
// velocity.applyEuler(rotation);
const quaternion = new THREE.Quaternion();
character.group.getWorldQuaternion(quaternion);
velocity.applyQuaternion(quaternion);
// collision
const origin = new THREE.Vector3().setFromMatrixPosition(character.view.matrixWorld);
const direction = new THREE.Vector3().copy(velocity).normalize();
const raycaster = new THREE.Raycaster(origin,direction);
for (const intersection of raycaster.intersectObjects(scene.collision)) {
if (intersection.distance < 0.5) {
// face normals ignore object quaternions
const normal = new THREE.Vector3().copy(intersection.face.normal);
const matrix = new THREE.Matrix4().extractRotation(intersection.object.matrixWorld);
normal.applyMatrix4(matrix);
// normal
normal.multiplyScalar(velocity.clone().dot(normal));
velocity.sub(normal);
}
}
// step
const delta = 0.001 / clock.getDelta();
velocity.multiplyScalar(delta);
// apply
character.group.position.add(velocity);
}
摄像机的设置与PointerLockControls帮助器非常相似,该摄像机是用于偏航和俯仰的“组对象”的子级。控制器输入是在其他地方定义的,因为它可以来自鼠标或游戏手柄,但是它返回归一化的值。
更准确地说,引起问题的部分在这里:
// gravity
if (scene.gravity.length() > 0) {
const origin = new THREE.Vector3().copy(character.view.position);
const direction = new THREE.Vector3().copy(scene.gravity).normalize();
const intersection = new THREE.Raycaster(origin,direction).intersectObjects(scene.collision).shift();
if (intersection) {
character.group.position.copy(intersection.point);
character.group.updateMatrix();
}
}
例如,如果我注释掉character.group.position.copy(intersection.point);
,则相机会像预期的那样移动(当然,它正在飞行),但是否则它将移动一帧的距离,然后重置为下一个帧。
我尝试了所有方式的updateMatrix(),updateMatrixWorld(),updateProjectionMatrix()和Object.matrixWorldNeedsUpdate = true,但遗憾的是。
我很抱歉使用代码的复制/粘贴而不是使用可测试的案例。谢谢您的宝贵时间。
答案 0 :(得分:0)
圣牛,我觉得很蠢... const origin = new THREE.Vector3().copy(character.view.position);
返回本地空间坐标,当然它会重置为原点!
用const origin = new THREE.Vector3().setFromMatrixPosition(character.view.matrixWorld);
替换它会给我正确的结果
那里有一堂课,关于呆呆地凝视代码太久了。我希望至少这个问题有一天能对某个人有所帮助。