How to put limitation on orbitCamera in Model Viewer Starter Kit

I just found orbitCamera in Model Viewer Starter Kit is quite useful, but what I wanna do with it is to set a limitaion on it.
For example, the camera is not allowed to get to the underground, so the camera’s position.y needs to be > 0

I put the code below in the function OrbitCamera.prototype._updatePosition

 if(position.y <= 0){
        position.y = 0.1;
    }
    this.entity.setPosition(position);

When I test it, the camera indeed doesn’t go to underground positions no matter how I move the mouse.
The scene of the problem is,
I keep the right mouse button down and moving the mouse up for seconds so the camera can get down to the ground definitely. Because the code above, the camera slides on the ground and won’t go downward anymore after it gets to the ground,

Then I still keep the right mouse button down and moving the muse down, the camera won’t go up immediately. It feels like sticking to the ground for a while, and then will go up…

I guess the problem is I need to change some delta vals to 0 when the camera gets to ground… I tried some vals but still doesn’t work…

Can anyone plz help?

The link to the project is https://playcanvas.com/project/482357/overview/ffff

SOLUTION

I just checked the orbitcamera and related input script, and finally make a solution. In mouseInput script,

MouseInput.prototype.pan = function(screenPoint) {
    var fromWorldPoint = MouseInput.fromWorldPoint;
    var toWorldPoint = MouseInput.toWorldPoint;
    var worldDiff = MouseInput.worldDiff;
    
    // For panning to work at any zoom level, we use screen point to world projection
    // to work out how far we need to pan the pivotEntity in world space 
    var camera = this.entity.camera;
    var distance = this.orbitCamera.distance;
    
    camera.screenToWorld(screenPoint.x, screenPoint.y, distance, fromWorldPoint);
    camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);


    
    worldDiff.sub2(toWorldPoint, fromWorldPoint);

// If the camera entity is very close to the ground, make sure the diff.y is positive, so the camera will move up
      if(this.entity.getPosition().y < 0.1){
        worldDiff.y = 0.1;
    }  
 
    this.orbitCamera.pivotPoint.add(worldDiff);        
    
    this.oldWorldDiff = worldDiff;
};
MouseInput.prototype.onMouseMove = function (event) {    
    var mouse = pc.app.mouse;
    if (this.lookButtonDown) {
// If the camera is very close to the ground, pitch it up
        if(this.entity.getPosition().y < 0.1){
             this.orbitCamera.pitch -= 0.1;
        }
        else{
        this.orbitCamera.pitch -= event.dy * this.orbitSensitivity;
        }
        this.orbitCamera.yaw -= event.dx * this.orbitSensitivity;
        
    } else if (this.panButtonDown) {
        this.pan(event);   
    }
    
    this.lastPoint.set(event.x, event.y);
};

The logic is quite simple, if the camera moves according to the delta vals like worldDiff, event.dy… So if the camera is very close to the ground, force these delta vals to make the camera go up. Simple, but still not a perfect solution tho…

You have not provided any links to code or project.
You very likely have multiple places where positioning is done, so have to add the condition you wrote above to those places.

I just forget adding link again… I editted my post and plz check it out

And your condition will create “blind zone” where camera.y is between 0 and 0.1. You need to do:

if (position.y < 0.1)
    position.y = 0.1;

Yes, I tried this before, but still didn’t make any difference.

I found the cameras moving is actrually controlled by mouseInut script,

MouseInput.prototype.onMouseMove = function (event) {    
    var mouse = pc.app.mouse;
    if (this.lookButtonDown) {
        this.orbitCamera.pitch -= event.dy * this.orbitSensitivity;
        this.orbitCamera.yaw -= event.dx * this.orbitSensitivity;
        
    } else if (this.panButtonDown) {
        this.pan(event);   
    }
    
    this.lastPoint.set(event.x, event.y);
};

MouseInput.prototype.pan = function(screenPoint) {
    var fromWorldPoint = MouseInput.fromWorldPoint;
    var toWorldPoint = MouseInput.toWorldPoint;
    var worldDiff = MouseInput.worldDiff;
    
    // For panning to work at any zoom level, we use screen point to world projection
    // to work out how far we need to pan the pivotEntity in world space 
    var camera = this.entity.camera;
    var distance = this.orbitCamera.distance;
    
    camera.screenToWorld(screenPoint.x, screenPoint.y, distance, fromWorldPoint);
    camera.screenToWorld(this.lastPoint.x, this.lastPoint.y, distance, toWorldPoint);

    worldDiff.sub2(toWorldPoint, fromWorldPoint);
       
    this.orbitCamera.pivotPoint.add(worldDiff);    
};

So I tried changing the code above by making the pitch and yaw equal to 0 if camera got to ground, but it didn’t work…

I’m not quite understanding what you are trying to do.

Do you want the camera to not move below the ground (while orbiting and/or panning)?
Do you want the pivot point to not move below the ground?

If the formal, it’s a little tricky as the orbit camera is define by:

  • yaw
  • pitch
  • distance from pivot point
  • pivot point

Changing the position of the camera directly without updating these properties will give unexpected behaviour.

Edit: Look at the OrbitCamera’s resetAndLookAtPoint function. That will allow you to move the camera to a specific position. It’s not the perfect solution here but may be enough for your needs.

Hi yaustar, what I wanna do is simply just keeping the camera always above the ground, in other words, camera.entity.getPosition().y > 0 always true.

I made a solution in my post, but still not a perfect one. If you have any suggestions, it’s apprecitated.

As mentioned before, you have to find all places where camera position is changed, either by setting it’s position directly or modifying it’s parent transformations, and add your condition there.

The unfortunate thing is that it isn’t simple as there are quite a few edge cases to this. So far, I can think of two ways:

  1. Check the camera position frame every frame. If position.y is lower than 0, use resetAndLookAtPoint to move it.
  2. As @max said, check in all the places where the camera position.y can change (panning and pitch in this case I think), and deal with it there. E.g If a change in pitch will cause the camera to go below 0, then don’t apply the change.

Yes, the solution in my post got the similar logic as your method #2. The camera moved according to the delta value got by mouse input each frame. The delta value decides how much the camera can pan and pitch every frame. The edge cases needs to be taken care of, so I’ll spend some time on it.

Also, method #1 is a good point. Guess I need to calculate the lookAtPoint by some methods. I’ll try it

I just got another solution.

I add rigidBody and collider to the camera , and add collider to the ground, too.

If the camera knocks to the ground, it will be bounced back because of the colliders…

But unfortunatelly, it seems not to work as expected…

If you are using physics then you really have to use forces to move the rigidbodies so you would need to rewrite that part of the orbit camera script.

Cool, so in playcanvas, I got to use forces to move stuff if I want them to be in the physic environment.

In pretty much any engine that is using physics (not just PlayCanvas), you will have to move the rigid bodies by forces, impulse or velocity for it to behave correctly/like a physics object.

On a side note, I had a go at restricting the Orbit Camera myself and got this far: https://playcanvas.com/project/482573/overview/orbit-camera-restrict

I just tried the project in the link. It’s a nice one, but guess we have to also deal with pan when camera’s y < 0.
A suggestion is like

OrbitCamera.prototype.addPivotPoint = function(arg){
    
    if(this.entity.getPosition().y < 0){
       this.pivotPoint.add(new pc.Vec3(arg.x, 0.01, arg.z));
    }
    else{
        this.pivotPoint.add(arg);
    }
};

Lift the pivotPoint up by 0.01 if camera’y < 0;
It can work, but the camera becomes a bit jumpy when it got to the ground (y < 0).

Dealing with pan is tricky as there are two ways to approach it:

  1. Restrict the pan so that when the camera is less than 0, the user cannot pan down any further
  2. Allow the user to pan as far as they would like but keep the camera at 0

Option 1 is pretty straightforward to do in the pivotPoint attribute set function. Option 2 is harder as you would have to change the pitch and distance while taking the lerping of values into account to keep it a smooth motion.

Is there any option to limitate the rotation (y) of the orbit camera?

Yes, there are attributes on the Orbit Camera script.


this? doesn’t change anything? sorry I’m not a coder

Ah, sorry. I assumed y as being the ‘pitch’ (rotating the camera up and down).

If you want to limit the yaw (moving the camera left and right) you need to add another set of attributes and clamp between them on yaw.

Bear in mind that doing this is going to cause issues for auto rotation that you asked about in the other thread.

Here is a quick and dirty version: https://playcanvas.com/editor/scene/619863

Not completely finished but should give you an idea.

1 Like