Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trackball control like rotation #385

Closed
madsendennis opened this issue Mar 5, 2023 · 10 comments
Closed

Trackball control like rotation #385

madsendennis opened this issue Mar 5, 2023 · 10 comments

Comments

@madsendennis
Copy link

Is your feature request related to a problem? Please describe.

I would like to use the controller with a "trackball" like control mechanism - like the one from the threejs examples.

This would allow for continuous rotation around an object without the viewing angle being locked - and a more natural rotation for inspecting objects from different sides where there is no obvious up vector.

Is this already possible with the controller through configuration? Or what would need to be updated to include this?

Thanks a lot for this great package.

Describe the solution you'd like

No response

Describe alternatives you've considered

No response

Additional context

No response

@yomotsu
Copy link
Owner

yomotsu commented Mar 8, 2023

Thanks for your feature request.
However, unfortunately, camera-controls can't do that.
The vertical rotation must be between 0 and Math.PI (which is 180degs) inclusive.

If you need Trackball control, please use TrackballControls in three.js.

@madsendennis
Copy link
Author

Hi @yomotsu , thanks for getting back to me.

I still prefer all the functionality that comes with camera controls. So I would need some mixture of the two. One way to "fix" it is to update the camera.up after each interaction in the camera-controls lib. This is also done in this repo: https://github.com/JaneliaSciComp/three-orbit-unlimited-controls
But I do not get the expected behaviour. Maybe you can easily spot the problem?

let camera = new THREE.OrthographicCamera(...)
camera.up.set(0.0, 0.0, 1.0);

let controls = new CameraControls(camera, container);

controls.addEventListener('sleep', () => {
  fixUp();
});

const fixUp = () => {
  const target = controls.getTarget();
  const view = new THREE.Vector3()
    .subVectors(target, camera.position)
    .normalize();
  // So first find the vector off to the side, orthogonal to both this.object.up and
  // the "view" vector.
  const side = new THREE.Vector3()
    .crossVectors(view, camera.up)
    .normalize();
  // Then find the vector orthogonal to both this "side" vector and the "view" vector.
  // This vector will be the new "up" vector.
  const up = new THREE.Vector3().crossVectors(side, view).normalize();
  camera.up.copy(up);
  controls.updateCameraUp();
};

I don't know if it is the updateCameraUp that is not able to handle a different 'up' vector, since it referes to _AXIS_Y?

@yomotsu
Copy link
Owner

yomotsu commented Mar 16, 2023

try this:

const fixUp = () => {
  const target = controls.getTarget();
  const view = new THREE.Vector3()
    .subVectors(target, camera.position)
    .normalize();
  // So first find the vector off to the side, orthogonal to both this.object.up and
  // the "view" vector.
  const side = new THREE.Vector3()
    .crossVectors(view, camera.up)
    .normalize();
  // Then find the vector orthogonal to both this "side" vector and the "view" vector.
  // This vector will be the new "up" vector.
  const up = new THREE.Vector3().crossVectors(side, view).normalize();
  camera.up.copy(up);
  
  const position = this.getPosition( new THREE.Vector3() );
  controls.updateCameraUp();
  this.setPosition( position.x, position.y, position.z );
};

Screen.Recording.2023-03-17.at.1.55.56.mp4

We also could add this as cameraControls.applyCameraUp().

@madsendennis
Copy link
Author

madsendennis commented Mar 18, 2023

Thanks. It works. I think that would be very handy. I don't know if there is a more intuitive way to automatically apply applyCameraUp than I do now:

controls.addEventListener('controlend', () => {
      controls.addEventListener('sleep', this.updateUpVector);
    });

If so, maybe there could even be an automaticUp flag that would automatically call the applyCameraUp(). Then the interaction is very close to a trackball controller I think.

@yomotsu
Copy link
Owner

yomotsu commented Mar 18, 2023

Good to hear that, but I think this disables (or breaks) some features of the camera control, such as reset( true ).

Perhaps automaticUp is better handled in userland as it causes confusions, because camera-controls is not a TrackballControls.

@yomotsu
Copy link
Owner

yomotsu commented Jul 22, 2023

Closing the issue due to age.

@yomotsu yomotsu closed this as completed Jul 22, 2023
@Anish-Someashwara
Copy link

Hey @yomotsu and @madsendennis , I am working on a threejs project in which I am using camera-controls which is a great tool for managing the controls.

Due to some project requirements I also want to extend the 'minPolarAnlge' (not completely 360 degree but little more than 180 degree) of the camera-controls. I found this thread very close to my requirements but I am not able to understand the solution provided above. I implementing the above solution in my project but didn't got the expected behaviour, it is behaving like a trackball control but I want it as same as camera-controls with some extension in 'minPolarAngle'.

so could you guys helps me in understanding this and extending the 'minPolarAngle' or could you provide a general code for this.

Thanks In Advance!

@yomotsu
Copy link
Owner

yomotsu commented Mar 9, 2024

Thanks for using camera-controls, however, unfortunately, camera-controls can't be a Trackball-controls. use the official trackball-controls or find another library.

@Anish-Someashwara
Copy link

@yomotsu Thanks for your response, I don't want trackball controls. I want controls same as camera-controls with some extension in polarAngle, I want to extend the polarAngle beyond 180 degrees. I through this thread is about the same problem which I am searching for.
So I am asking how I can extend the polarAngle , because everything working fine with camera-controls, except polarAnlge.

Thanks!

@madsendennis
Copy link
Author

Hi @Anish-Someashwara ,
Like you I also wanted to use the camera-controls instead of trackball-controls, but had the problem with the rotation getting "stuck".
What I ended up doing was extending the camera-controller as @yomotsu suggested in this thread fixUp.
This will will make it possible to rotate 180 degrees before the control getting stuck, by letting go of the interaction I then recalculate the up vector which makes it possible to continue rotating around the object. For me, this works well enough.

A minimal example of what I do and what events I use:

import CameraControls from 'camera-controls';
import * as THREE from 'three';

class MyCameraControls extends CameraControls {
  constructor(camera, domElement) {
    super(camera, domElement);
    this.camera = camera;
    this.draggingSmoothTime = 0.0;
  }
  enableAutoUp = () => {
    this.addEventListener('controlend', this.controlEndEvent);
  };
  controlEndEvent() {
    this.addEventListener('sleep', this.updateUpVector);
  }
  updateUpVector = () => {
    this.removeEventListener('sleep', this.updateUpVector);
    const currentPosition = this.camera.position.clone();
    const view = new THREE.Vector3()
      // eslint-disable-next-line no-underscore-dangle
      .subVectors(this._target.clone(), this.camera.position.clone())
      .normalize();
    // So first find the vector off to the side, orthogonal to both this.object.up and
    // the "view" vector.
    const side = new THREE.Vector3()
      .crossVectors(view, this.camera.up)
      .normalize();
    // Then find the vector orthogonal to both this "side" vector and the "view" vector.
    // This vector will be the new "up" vector.
    const up = new THREE.Vector3().crossVectors(side, view).normalize();
    this.camera.up.copy(up);

    this.updateCameraUp();

    this.setPosition(
      currentPosition.x,
      currentPosition.y,
      currentPosition.z,
      false,
    );
  };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants