I'm playing around with Three.js and WebGL and can't quite get the controls the way I want. I chose to try to "roll my own" controls since Three.js's FirstPersonControls do not use pointer lock.
Anyway, I took most of my code from the built-in FirstPersonControls, converted it to use pointer lock (movementX
instead of pageX - offset
), but I am having trouble smoothing the look motion.
Here is my onMouseMove
(using originalEvent
since it is a jquery event):
onMouseMove: function(e) { if(!document.pointerLockElement) return; var moveX = e.originalEvent.movementX || e.originalEvent.mozMovementX || e.originalEvent.webkitMovementX || 0, moveY = e.originalEvent.movementY || e.originalEvent.mozMovementY || e.originalEvent.webkitMovementY || 0; //Update the mouse movement for coming frames this.mouseMovementX = moveX; this.mouseMovementY = moveY; }
And my Controls.update()
(called on each animation frame, with the THREE.Clock
delta):
update: function(delta) { if(this.freeze) { return; } //movement, works fine if(this.moveForward) this.camera.translateZ(-(actualMoveSpeed + this.autoSpeedFactor)); if(this.moveBackward) this.camera.translateZ(actualMoveSpeed); if(this.moveLeft) this.camera.translateX(-actualMoveSpeed); if(this.moveRight) this.camera.translateX(actualMoveSpeed); ///////// //ISSUES ARE WITH THIS CODE: ///////// //look movement, really jumpy this.lon += this.mouseMovementX; this.lat -= this.mouseMovementY; this.lat = Math.max(-85, Math.min(85, this.lat)); this.phi = (90 - this.lat) * Math.PI / 180; this.theta = this.lon * Math.PI / 180; this.target.x = this.camera.position.x + 100 * Math.sin(this.phi) * Math.cos(this.theta); this.target.y = this.camera.position.y + 100 * Math.cos(this.phi); this.target.z = this.camera.position.z + 100 * Math.sin(this.phi) * Math.sin(this.theta); this.camera.lookAt(this.target); }
This code does work, but moving the camera is jumpy as the mouse moves around. I could really use some help figuring out how to smooth it.
You can see what I mean by "jumpy" here. I'm new to Three.js, WebGL, and just 3D in general so any help is appreciated.
Thanks,
-Chad
EDIT After working with @przemo_li, here is the working code he came up with:
onMouseMove: function(e) { if(!document.pointerLockElement) return; var moveX = e.originalEvent.movementX || e.originalEvent.mozMovementX || e.originalEvent.webkitMovementX || 0, moveY = e.originalEvent.movementY || e.originalEvent.mozMovementY || e.originalEvent.webkitMovementY || 0; //Update the initial coords on mouse move this.mouseMovementX += moveX; //aggregate mouse movements as a total delta delta this.mouseMovementY += moveY; }, update: function(delta) { if(this.freeze) { return; } //movement if(this.moveForward) this.camera.translateZ(-(actualMoveSpeed + this.autoSpeedFactor)); if(this.moveBackward) this.camera.translateZ(actualMoveSpeed); if(this.moveLeft) this.camera.translateX(-actualMoveSpeed); if(this.moveRight) this.camera.translateX(actualMoveSpeed); //look movement this.lon += this.mouseMovementX; this.lat -= this.mouseMovementY; this.mouseMovementX = 0; //reset mouse deltas to 0 each rendered frame this.mouseMovementY = 0; this.phi = (90 - this.lat) * Math.PI / 180; this.theta = this.lon * Math.PI / 180; if(this.constrainVertical) { this.phi = THREE.Math.mapLinear(this.phi, 0, Math.PI, this.verticalMin, this.verticalMax); } this.target.x = this.camera.position.x + 100 * Math.sin(this.phi) * Math.cos(this.theta); this.target.y = this.camera.position.y + 100 * Math.cos(this.phi); this.target.z = this.camera.position.z + 100 * Math.sin(this.phi) * Math.sin(this.theta); this.camera.lookAt(this.target); }