Search code examples
three.jscameracontrols

Keeping camera above ground (using OrbitControls.js)


So I have a very simple situation where the ground plane is basically where y=0 is and I want to keep the camera above the ground at all time. I also want good controls that feel intuitive (and are touch-compatible) and I figured out that the OrbitControls.js seems best suited for this, also because there I can easily limit the polar angle by setting maxPolarAngle to something less or equal Math.PI/2 (quarter turn).

Still, even doing that the user can pan below the ground unless panning is disabled altogether (which I don't want to). Manually limiting so that y never goes negative felt weird but I figured that simply ignoring any changed on the y axis by e.g. changing line 165 (panUp function) to the following

panOffset.set( te[ 4 ], 0, te[ 6 ] );
panOffset.normalize();

led to a quick and dirty solution that did about what I wanted.

But now the user can now only change the camera height by zooming.

Can you think of any better solution? Maybe this thread can serve as food for thought for an official solution, I am sure I wouldn't be the only one benefiting from such a solution.

/edit: I wasn't normalizing the offset vector at first which led to another issue, changed now.


Solution

  • Just in case someone needs an answer:

    You find the angle relative to the controls target and the ground position of the camera (regardless of altitude) and assign the maxPolarAngle. Adjust for your up axis, mine was Y. Inside the controls change event:

    var centerPosition = controls.target.clone();
    centerPosition.y = 0;
    var groundPosition = camera.position.clone();
    groundPosition.y = 0;
    var d = (centerPosition.distanceTo(groundPosition));
    
    var origin = new THREE.Vector2(controls.target.y,0);
    var remote = new THREE.Vector2(0,d); // replace 0 with raycasted ground altitude
    var angleRadians = Math.atan2(remote.y - origin.y, remote.x - origin.x);
    controls.maxPolarAngle = angleRadians;