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

OrbitControls issue #27104

Closed
LiveNathan opened this issue Nov 2, 2023 · 11 comments
Closed

OrbitControls issue #27104

LiveNathan opened this issue Nov 2, 2023 · 11 comments
Labels

Comments

@LiveNathan
Copy link

LiveNathan commented Nov 2, 2023

Description

Animating a camera movement works beautifully, until you change the default up, after which there's an annoying snap rotation at the end. The default up is necessary for architectural design applications.

Here's my original StackOverflow post.

Reproduction steps

I have created a minimal reproducible example on Codepen and I have posted the question on GitHub.

Code

import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

camera.position.z = 5;

const controls = new OrbitControls(camera, renderer.domElement);
controls.object.up.set(0, 0, 1);
controls.update();

const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

function moveCamera() {

  const box = new THREE.Box3();
  box.expandByObject(cube);
  const center = box.getCenter(new THREE.Vector3());
  const size = box.getSize(new THREE.Vector3());
  const maxSize = Math.max(size.x, size.y, size.z);
  const fitHeightDistance = maxSize / (2 * Math.atan((Math.PI * camera.fov) / 360));
  const fitWidthDistance = fitHeightDistance / camera.aspect;
  const offset = 5;
  const distance = offset * Math.max(fitHeightDistance, fitWidthDistance);

  controls.maxDistance = distance * 2;
  controls.target = center;

  let newPosition = new THREE.Vector3(center.x, center.y, center.z + distance);
  const timeline = gsap.timeline({ defaults: { duration: 1 } });
  timeline.clear();
  timeline.fromTo(
    camera.position,
    { ...camera.position },
    {
      ...newPosition,
      onUpdate: function () {
        controls.update();
      }
    }
  );

  camera.near = distance / 10;
  camera.far = distance * 10;

  camera.updateProjectionMatrix();
}

document.getElementById("move-camera-button").addEventListener("click", () => {
  moveCamera();
});

Live example

Codepen

Screenshots

https://youtu.be/Djo80EMwfvA

Version

https://threejs.org/build/three.module.js

Device

Desktop

Browser

Chrome

OS

MacOS

@Mugen87
Copy link
Collaborator

Mugen87 commented Nov 2, 2023

Would something like #18829 fix your issue?

@WestLangley
Copy link
Collaborator

The problem is with your app. You are setting the final camera position to be on the z-axis, which is not valid when the z-axis is the camera up-direction. ( camera.lookAt() is not well-defined when looking in the direction of +/- camera.up.)

@LiveNathan
Copy link
Author

Would something like #18829 fix your issue?

Thanks Mugen. Maybe. But, DEFAULT_UP is the first thing that is set. When I look at camera.up I see this.up = Object3D.DEFAULT_UP.clone();, which makes me think I shouldn't need to set camera.up. That being said, I'm will to try it. I'll need to see where it should be.

@LiveNathan
Copy link
Author

The problem is with your app. You are setting the final camera position to be on the z-axis, which is not valid when the z-axis is the camera up-direction. ( camera.lookAt() is not well-defined when looking in the direction of +/- camera.up.)

Thanks West. Could you tell me more. I don't want to have to manage two axes. I have not set camer.up, but maybe it is set implicitly? I'll take a look at camera.lookAt().

@WestLangley
Copy link
Collaborator

@LiveNathan: see #11543 for related info.

@LiveNathan
Copy link
Author

Ok, I found that if I set camera.up.set(0, 1, 0); temporarily at the beginning of moveCamera() and the reset it at the end:

timeline.fromTo(
    camera.position,
    { ...camera.position },
    {
      ...newPosition,
      onUpdate: function () {
        controls.update();
      },
      onComplete: function () {
        camera.up.set(0, 0, 1);
      }
    }
  );

Then it seems to fix the problem at first, but there's a jump at the beginning, so I think it just moves the problem.

@LiveNathan
Copy link
Author

@LiveNathan: see #11543 for related info.

checking!

@LiveNathan
Copy link
Author

@LiveNathan: see #11543 for related info.

So, from this commit, it looks like I shouldn't need to worry because the issue has already been solved. Not sure how that helps me. I'm still experiencing it. Sorry if I'm not understanding.

@Mugen87 Mugen87 added the Addons label Nov 3, 2023
@LiveNathan
Copy link
Author

I spent today trying a bunch of different solution. Nothing worked. As far as I can tell this is still an issue, but I'd love to be wrong.

@WestLangley
Copy link
Collaborator

You should not set the look direction to be parallel to the camera up direction, because doing so causes the camera orientation to be under-determined. In such a case, an arbitrary camera orientation is selected, which is why you see the final rotation at the end.

If you need more help understanding the issue, you can request help on https://discourse.threejs.org.

@LiveNathan
Copy link
Author

Thanks West! I have tried various solutions to avoid the parallel lookAt, without success.

I'll go ahead and close the issue. Would you be willing to answer my StackOverflow question linked in my original post? It's had lots of views but no answers or solutions.

@WestLangley WestLangley changed the title OrbitControls does not respect THREE.Object3D.DEFAULT_UP OrbitControls issue Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants