I have successfully added a really nice mouse movement to a scene in three.js where the camera sits inside the scene, facing one of four walls. Moving the mouse left or right pans and rocks the scene slightly.
If you keep holding the mouse over one side of the screen though, you end up 'flying' outside of the scene and now viewing the entire 3D object from the outside, no longer inside it.
I was wondering how I can update my code below to limit the max amount you can move to the left or right, so that you can't end up outside the scene?
If I can avoid adding another library such as Orbit Controls that would be ideal, but if it's the only way then I will do that. I feel like I have been close with adding some kind of Math.Max to the camera position in my function animate() but haven't had any success so far.
Thanks in advance for any help!
window.addEventListener("load", loadGltf, false);
window.addEventListener("resize", onWindowResize, false);
const progressBar = document.querySelector("progress");
//store our imported glTF scene when loaded successfully
const gltfStore = {};
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
container = document.getElementById( 'container' );
//camera
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 0, 0);
camera.lookAt(0, 0, 5);
windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2,
mouseX = 0,
mouseY = 0;
//re-establish camera view on window resize
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
//lighting
const lightFill = new THREE.PointLight(0xffffff, 1, 500);
lightFill.position.set(0, 0, 5);
scene.add(lightFill);
const lightKey = new THREE.PointLight(0xffffff, 1, 500);
lightKey.position.set(20, 0, 20);
scene.add(lightKey);
const loader = new THREE.GLTFLoader();
function loadGltf() {
loader.load(
"<?php echo get_template_directory_uri();?>/objects/SM_LookDev_TextureTest_FromFBX.glb",
//onLoad
function(gltf) {
scene.add(gltf.scene);
mesh = gltf.scene;
//set material emissive to 0
gltf.scene.children[0];
gltfStore.scene = gltf.scene;
document.addEventListener("mousemove", onMouseMove);
}
);
container.appendChild(renderer.domElement);
// Mouse movement
function onMouseMove(event) {
mouseX = (event.clientX - windowHalfX) / 10;
mouseY = (event.clientY - windowHalfY) / 30;
}
function getMouseX(event) {
if (event.type.indexOf("touch") == -1)
return event.clientX;
else
return event.touches[0].clientX;
}
function getMouseY(event) {
if (event.type.indexOf("touch") == -1)
return event.clientY;
else
return event.touches[0].clientY;
}
function animate() {
requestAnimationFrame(animate);
camera.position.x += (mouseX - camera.position.x) * .0005;
camera.position.y += (-mouseY - camera.position.y) * .0003;
camera.lookAt(0,0,10);
renderer.render(scene, camera);
}
animate();
}
Three.js comes with some utility methods in its MathUtils
class that can help with this. You could use THREE.MathUtils.clamp
to limit the minimum and maximum values of mouseX
and mouseY
:
function onMouseMove(event) {
mouseX = THREE.MathUtils.clamp((event.clientX - windowHalfX) / 10, -20, 20);
mouseY = THREE.MathUtils.clamp((event.clientY - windowHalfY) / 30, -10, 10);
}
The min & max values of -20, 20
, etc depend on the bounds of your .gltf
object, so you'll have to adjust those accordingly.
This is just a helper method that uses JavaScript's native Math.min()
and Math.max()
internally to "clamp" the value.
Before Three.js revision 113, the THREE.MathUtils
class used to be called THREE.Math
but this could cause a conflict with JavaScript's native Math
class. Make sure you're using the correct name based on the version of Three.js you're using, see here for more details.