I'm encountering an issue with FPS camera controls in a three.js scene. My approach involves using a Raycaster
to determine the camera group's position by intersecting it with the scene along the Y axis (a makeshift gravity setup) and then applying user input for movement. However, the camera group's position keeps resetting to the intersection location on every frame, essentially sticking you in place.
I suspect this problem may be due to either an updateMatrix()
issue or passing a Vector3
by reference somewhere, but I'm struggling to pinpoint the exact cause. Can someone please assist me? Here is the code snippet for better understanding:
re-renderer.setAnimationLoop((event) => {
if (clock.running) {
update();
renderer.render(scene, character.view);
}
});
clock.start();
//
const update = () => {
// velocity
const speed = new THREE.Vector3();
speed.x = input.controller.direction.x;
speed.z = input.controller.direction.y;
speed.clampLength(0, 1);
if (speed.z < 0) {
speed.z *= 1.4;
}
// gravity
if (scene.gravity.length() > 0) {
const origin = new THREE.Vector3().copy(character.view.position);
const dir = new THREE.Vector3().copy(scene.gravity).normalize();
const interact = new THREE.Raycaster(origin, dir).intersectObjects(scene.collision).shift();
if (interact) {
character.group.position.copy(intersect.point);
character.group.updateMatrix();
}
}
...
The camera configuration is similar to the PointerLockControls helper, with the camera as a child of a Group Object for yaw and pitch. The controller input, sourced from either a mouse or gamepad, returns normalized values.
The main culprit seems to be here:
// 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 inter = new THREE.Raycaster(origin, direction).intersectObjects(scene.collision).shift();
if (inter) {
character.group.position.copy(intersection.point);
character.group.updateMatrix();
}
}
By commenting out
character.group.position.copy(intersection.point);
, the camera moves correctly (albeit floating), but otherwise it moves a single frame's distance before reverting back to the intersection point on the next frame.
I've experimented with various methods like updateMatrix()
, updateMatrixWorld()
, updateProjectionMatrix()
, and setting Object.matrixWorldNeedsUpdate
to true, yet haven't found a solution.
Apologies for not providing a testable scenario and instead relying on code snippets. I appreciate your time and assistance.