I want to be able to look all the way down/up

I am trying to make a game with a perspective camera and I want to Be able to look all the way down and up. But when I try it stops me at some kind of limit. is there a way to extend that limit so I can look all the way up/down?

OrbitControls don’t allow upside-down orientation, consider using Arcball- or TrackballControls instead.

I am not using orbit controls.
this is the code for controlling the camera.

canvas.addEventListener('mousemove', (event) => {
    if (document.pointerLockElement === canvas) {
        const movementX = event.movementX;
        const movementY = event.movementY;
        camRotation -= toDegrees(movementX * mouseSensitivity);
        euler.y -= movementX * mouseSensitivity;
        euler.x -= movementY * mouseSensitivity;
        euler.x = Math.min(Math.max(euler.x, -1.0472), 1.0472);
        euler.minPolarAngle=0;
        camera.quaternion.setFromEuler(euler);
    }
});

I Prefur degrees if you were wondering.
also camrotation is to help with movement (which is not related).

Could you replace the last two lines with something like this?

camera.rotation.copy(euler);

It didn’t work. (it did that exact same thing)
Also doesn’t that just copy the properties of euler into the camera?
Also I thought that I could use minPolarAngle to change the minimum polar angle but than I found out that it only works for orbit controlls.

For a camera view, you need to observe the “up”-direction, which is typically defined as the ratio of y-coordinate vs. x or z coordinate. Looking straight up/down at the zenit/nadir, the x/z coordinates become zero and the above ratio will be undefined (at best). It may be sufficient for you to look at slightly less than exactly ±90°. The camera’s fov would bring the south/north pole into view nevertheless, albeit not exactly centered.

Maybe that would be good enough?

That’s odd. I have never used the particular format you are using, but you indicate that it is working fine until you hit the limit.

My approach is more fragmented.

I initialize the listener with this command:

renderer.domElement.addEventListener("mousemove", onMouseMove, false);

I then have two subroutines - one which responds to the MouseMove event and one which positions the camera.

Here is the first subroutine:

function onMouseMove(event) {
    // Latitude
    lld.x = (onPointerDownY - event.clientY)*mmr.z + onPointerDownLat;
    if (mmr.x) lld.x = Math.max(-mmr.x, Math.min(mmr.x, lld.x));
    // Longitude
    lld.y = (event.clientX - onPointerDownX)*mmr.z + onPointerDownLon;
    if (mmr.y) lld.y = Math.max(-mmr.y, Math.min(mmr.y, lld.y));
}

where:

onPointerDownX and Y are variables
onPointerDownLat and Lon are variables
mmr = new THREE.Vector3(90,0,0.2); // constant: min(x)/max(y) rotation and rotation speed (z)
lld = new THREE.Vector3(0,0,0); // variable: lat(x)/lon(y) and distance(z)

Here is the second subroutine:

function moveCamera(camera) {
    camera.position.z = -lld.z; // Move Camera In/Out
    camera.rotation.x = Mod360(lld.x)*DegRad; // Latitude
    camera.rotation.y = Mod360(lld.y)*DegRad; // Longitude
}

where:

Mod360 is a function that limits degrees to 360
DegRad = Math.PI/180;

All the rotations are in degrees until the end.

It seems like you have all the same type of instructions.

I tried it, but this time, it didn’t show anything. After I did some debugging, I found that it was setting the camera rotation x, y, and z to NaN. I looked even further and found out that the lld.x and lld.y were also being set to NaN.

I know that (onPointerDownY - event.clientY) should do something like get how much the mouse has moved on the y axis so I set onPointerDownX and onPointerDownY to the previous mouse values.
Anyway, my question is what do I do with onPointerDownLat and onPointerDownLon?

this isn’t right. delete it:

        euler.minPolarAngle=0;

this is whats limiting the rotation:

        euler.x = Math.min(Math.max(euler.x, -1.0472), 1.0472);

those numbers are wrong, it should be Math.PI/2 to get 90 degrees up/down

        euler.x = Math.min(Math.max(euler.x, -Math.PI*.5), Math.PI*.5);
1 Like

In my haste to get you an answer, it looks like I only gave you half the story.

Before moving the camera, you generally want to press a key or button to activate panning. In my case, I press the mouse button. So we need to add the following variable:

let pan = 0;

To use the mouse button, we need to initialize the mouse button listener with these additional commands:

renderer.domElement.addEventListener("mousedown", onMouseDown, false);
renderer.domElement.addEventListener("mouseup", onMouseUp, false);

Then we need to add the following event handlers:

function onMouseDown(event) {
    event.preventDefault();
    pan = 1;
    onPointerDownX = event.clientX;
    onPointerDownY = event.clientY;
    onPointerDownLon = lld.y;
    onPointerDownLat = lld.x;
}

function onMouseUp(event) {
	pan = 0;
}

As you can see, this is where the onPointerDown variables are used. They initialize the computation of the mouse movement And that is probably why you were getting errors.

We need to modify the onMouseMove event handler to activate only when panning is activated. Here is the modified subroutine:

function onMouseMove(event) {
    if (pan) { // Only compute if panning
        lld.x = (onPointerDownY - event.clientY)*mmr.z + onPointerDownLat;
        if (mmr.x) lld.x = Math.max(-mmr.x, Math.min(mmr.x, lld.x));
        lld.y = (event.clientX - onPointerDownX)*mmr.z + onPointerDownLon;
        if (mmr.y) lld.y = Math.max(-mmr.y, Math.min(mmr.y, lld.y));
    }
}

The moveCamera function is the same, except that the parenthetical reference to the camera is not needed and the computation of distance can be eliminated.:

function moveCamera() {
    camera.rotation.x = Mod360(lld.x)*DegRad;
    camera.rotation.y = Mod360(lld.y)*DegRad;
}

Also, to make this work right you may need to set the camera rotation order to:

camera.rotation.order = "YXZ";

Here is the CodePen example. I am using WebGPU, but it works the same for WebGL.

The result of all this is that you can now use the mouse to rotate up and down all the way to 90 degrees. And when you are pointed straight up or down moving the mouse left or right will cause the sky to rotate around a central point - which is what I think you would want.

I hope this gives you a useful option.

FYI - When I experimented with changing the lld variable to a euler variable, strange things happened. The camera would bank, depending on your longitude so that the horizon was not level and the controls would eventually switch.

If you want to modify the camera to also look inwards, I can show you how to attach the camera to a couple of linked meshes - kind of like using a “selfie stick”.

You are a GENEUS! I had no idea the is was Math.min/Math.max!