Camera Position Not Updating Correctly After Panning – Values Not Applied Properly

Hi,

I have multiple scenes, and for each scene, I set the camera differently. I’m using a single camera and adjusting its position through scripts, as I find manually configuring it in the Unity Inspector challenging. Instead, I run the project locally, position the camera as needed, and print its worldPosition and worldRotation values to use them for setting the camera.

The issue arises when I pan the camera, print the updated values, and use them to reposition the camera—it seems that the panned values are not being applied correctly.

Here, the cam object stores the camera’s values:

setBaseCameraPosition(cam: Camera) {
    if (!this.baseCamera) return;
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      //baseCamOrbitControl.fitCamera(this.goTarget);
      baseCamOrbitControl?.setLookTargetPosition(this.goTarget, 1);
      baseCamOrbitControl?.setCameraTargetPosition(cam.gameObject, 1);
    }
  }

Hi Ashok,

The issue you’re experiencing with the camera position not updating correctly after panning may relate to how the camera’s target position and look-at position are set in your code.

In your setBaseCameraPosition function, ensure that both the camera’s target position and its position are being updated properly with respect to any transformations applied during panning.

Here is a recommended adjustment to check if the position values are being copied and set correctly:

setBaseCameraPosition(cam: Camera) {
    if (!this.baseCamera) return;
    
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
        // Get current camera position and orientation
        const currentPosition = cam.worldPosition.clone();
        const currentRotation = cam.worldRotation.clone();

        // Set the target position based on the panned values
        baseCamOrbitControl.setLookTargetPosition(this.goTarget, 1);
        baseCamOrbitControl.setCameraTargetPosition(currentPosition, 1); // Ensure to use the updated position
    }
}

Make sure that this.goTarget and other values are being set correctly before calling setBaseCameraPosition. The setCameraTargetPosition method allows you to specify whether the movement should be immediate or interpolated over a duration. Using a value of 1 will move it immediately to the target position.

If the problem persists, consider checking if any other scripts or components are affecting the camera’s position or if the correct values are being printed when you expect to set them.

You might want to confirm if the OrbitControls is properly enabled and whether there are other interfering systems affecting camera controls.

If you need further assistance, please provide more details about how and where the camera positioning happens, as well as relevant snippets of any related code.

Feel free to check the Needle Engine documentation for more insights on camera manipulation with the OrbitControls class: OrbitControls API.

1 replies left - Get a PRO license for more AI replies.
thread_FTOQeQUHHeZPOkoXFDra77ZD
Reply to this message to continue the conversation

As you can see in this video im panning before getting the positions and when i use these values in unity, its works except the panning part.
Video: Game creator Ks's Video - Feb 6, 2025

The bot is most likely correct - Do you also use the Orbitcontrols component?

This is probably due to the fact that you need to update the OrbitControls target as well

See my reply here: Issue with Camera Reset Functionality After Using Pan - #5 by marcel

Regarding positioning the camera: you can move the scene camera in Unity and apply your scene camera position with the click of a button to your main camera too. No need to copy values:

As you can see here, I set both, but it sets to position before pan

Sorry but that’s not enough information to help unfortunately - can you show your full script?

Yeah, sure.

setBaseCameraPosition(cam: Camera) {
    if (!this.baseCamera) return;
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      //baseCamOrbitControl.fitCamera(this.goTarget);
      baseCamOrbitControl?.setLookTargetPosition(this.goTarget, 1);
      baseCamOrbitControl?.setCameraTargetPosition(cam.gameObject, 1);
    }
  }

i tried like this too found out that pos values are being set correctly but rot values are not

setBaseCameraPositionWithVector(pos: Vector3,rot:Vector3) {
    if (!this.baseCamera) return;
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      //baseCamOrbitControl.fitCamera(this.goTarget);
      baseCamOrbitControl?.setLookTargetPosition(this.goTarget, 1);
      baseCamOrbitControl?.setCameraTargetPosition(pos, 1);
      this.baseCamera.setWorldRotation(rot.x,rot.y,rot.z);
    }
  }

Could you please share the full script so I can better understand what your references are (this.goTarget)?

import { Behaviour, serializable, GameObject, Camera, FileReference, SceneSwitcher, OrbitControls, Vec3 } from "@needle-tools/engine";

import { ComponentData, ModelSourceData, ProcedureModuleData, ProcedureSequenceData, SceneData } from "./CustomClassesContainer";
import { StepDataSource } from "./StepDataSource";
import { Vector3 } from "three";

export class ComponentDataContainer extends Behaviour {
  @serializable()
  componentObjects: GameObject[] = [];

  @serializable(ComponentData)
  sequenceComponentHideList: ComponentData[] = [];

  @serializable(Camera)
  baseCamera?: Camera;

  @serializable(ModelSourceData)
  modelSourceData?: ModelSourceData;

  @serializable(FileReference)
  jsonData?: FileReference;

  @serializable(StepDataSource)
  currentStepDataSource?: StepDataSource | null;

  @serializable(SceneSwitcher)
  sceneSwitcher?: SceneSwitcher;

  sequenceIndex: number = 0;

  @serializable(SceneData)
  sceneContainer: SceneData[] = [];

  currentProcedure?: ProcedureModuleData | undefined;
  currentSequence?: ProcedureSequenceData | undefined;
  currentProcedureScenesData: SceneData[] = [];
  isInstallProcedure: boolean = false;
  goTarget?: GameObject;

  public static instance: ComponentDataContainer;

  awake() {
    ComponentDataContainer.instance = this;
    this.loadInitialScene();
  }

  start(): void {}

  setBaseCameraPosition(cam: Camera) {
    if (!this.baseCamera) return;
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      //baseCamOrbitControl.fitCamera(this.goTarget);
      baseCamOrbitControl?.setLookTargetPosition(this.goTarget, 1);
      baseCamOrbitControl?.setCameraTargetPosition(cam.gameObject, 1);
    }
  }

  setBaseCameraPositionWithVector(pos: Vector3,rot:Vector3) {
    if (!this.baseCamera) return;
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      //baseCamOrbitControl.fitCamera(this.goTarget);
      baseCamOrbitControl?.setLookTargetPosition(this.goTarget, 1);
      baseCamOrbitControl?.setCameraTargetPosition(pos, 1);
      //this.baseCamera.setWorldRotation(rot.x,rot.y,rot.z);
    }
  }

  async setModelSourceData() {
    const data = await this.jsonData?.loadText();
    if (data) this.modelSourceData = JSON.parse(data);
  }

  async loadInitialScene() {
    await this.setCurrentProcedureScenesData();
    if (this.currentProcedureScenesData[0].scene) this.sceneSwitcher?.switchScene(this.currentProcedureScenesData[0].scene);
  }

  async setCurrentProcedureScenesData() {
    const pid = parseInt(new URLSearchParams(window.location.search).get("pid") || "");
    await this.setModelSourceData();
    this.currentProcedure = this.modelSourceData?.languageList[0].procedureList.find((pro) => pro.procedureId === pid);
    // console.log(this.currentProcedure);
    if (!this.currentProcedure) {
      console.log("Procedure NOT found");
      return;
    }
    const scenes: SceneData[] = [];
    for (let i = 0; i < this.currentProcedure?.sequnenceList.length; i++) {
      const scene: SceneData | undefined = this.sceneContainer.find(
        (sce) => sce.id === this.currentProcedure?.sequnenceList[i].sequenceId
      );
      if (scene) scenes.push(scene);
    }
    this.currentProcedureScenesData = [...scenes];
  }

  sceneChangeEvent() {
    //console.log("Scene loaded");
  }

  loadInitialRemoveSequence() {
    this.isInstallProcedure = false;
    if (this.currentProcedureScenesData[0].scene) this.sceneSwitcher?.switchScene(this.currentProcedureScenesData[0].scene);
    this.sequenceIndex = 0;
    //console.log(this.sceneSwitcher?.currentlyLoadedScene);
    if (
      this.sceneSwitcher?.currentlyLoadedScene?.asset?.userData?.name ===
      this.currentProcedureScenesData[0].scene?.asset?.userData?.name
    ) {
      this.sceneSwitcher?.reload();
    }
  }

  loadInitialInstallSequence() {
    this.isInstallProcedure = true;
    const reversed = this.currentProcedureScenesData.toReversed();
    if (reversed[0].scene) this.sceneSwitcher?.switchScene(reversed[0].scene);
    this.sequenceIndex = 0;
    //console.log(this.sceneSwitcher?.currentlyLoadedScene?.asset.userData.name);
    //console.log(reversed[0].scene);
    if (this.sceneSwitcher?.currentlyLoadedScene?.asset?.userData?.name === reversed[0].scene?.asset?.userData?.name) {
      this.sceneSwitcher?.reload();
    }
  }
}

What is goTarget? Is it assigned from Unity? If so then it’s missing a @serializable(Object3D) (same as componentObjects: GameObject[] at the top need a @serializable(Object3D)

Yes, it is assigned through Unity. It is the model from source scene. It worked fine without @Serializable, so I assumed it wasn’t necessary.

The issue I’m facing is caused by OrbitControls.

I’ve attached a video to better illustrate the problem.

As shown in the video, when the OrbitControls script is turned off, the camera’s position and rotation are set correctly. However, when I enable orbitControls, it correctly applies the position but changes the rotation to an unintended value.
Looking for a solution to this ASAP.
video URL: Game creator Ks's Video - Feb 12, 2025

setBaseCameraPositionNew(cam: Camera) {
    if (!this.baseCamera || !cam) return;
    //this.baseCamera.gameObject.position.copy(cam.gameObject.position);
    //this.baseCamera.gameObject.quaternion.copy(cam.gameObject.quaternion);
    const quaternion = new Quaternion(0.00003714274585154551, 0.9813547287797059, 0.1922052521602807, -0.00018964210848349257);
    const baseCamOrbitControl = GameObject.getComponent(this.baseCamera.gameObject, OrbitControls);
    if (baseCamOrbitControl) {
      baseCamOrbitControl.autoFit = false;
      baseCamOrbitControl.autoTarget = false;
    }
    this.baseCamera.setWorldPosition(0.025, 0.208, -0.346);
    this.baseCamera.gameObject.setRotationFromQuaternion(quaternion);
    //this.baseCamera.setWorldRotation(-161,2.56,179,false);
    console.log("iueo");
  }

Hello, as said in my reply here: OrbitControls is using a threejs object as a look target. When you use OrbitControls and you want to change the rotation of your camera you need to set the OrbitControls target position - otherwise it will be overriden the next frame again. This is how three.js OrbitControls fundamentally works and it is not a bug.

Hi, thanks for your response!

Just to clarify, if we are using OrbitControls, does that mean we cannot directly set the rotation by assigning (x, y, z, w) values like this?
this.baseCamera.gameObject.setRotationFromQuaternion(quaternion);
Instead, do we need to set the rotation by using lookTarget and cameraTargetPosition like this?

baseCamOrbitControl?.setLookTargetPosition(this.target, 1);
baseCamOrbitControl?.setCameraTargetPosition(cam.gameObject, 1);

I just want to confirm if my understanding is correct.

That’s correct.

You can also modify the position of the OrbitControls target directly if you prefer that.

So under the hood we use three’s OrbitControls (see target docs)

This is accessable via the Needle Engine OrbitControls component: needleOrbitControls.controls so to get access to the target of three.js you can use needleOrbitControls.controls.target and change it’s position(!) since it’s a Vector3.

Thanks! I have one more question.

I have multiple scenes: a source scene and several child scenes. Currently, I control the source scene’s camera using this approach, and I switch between scenes using the SceneSwitcher.switchScene method.

  1. If my child scenes contain their own cameras, will those cameras be rendered when switching scenes?
  2. If I want to reset the child scene’s camera (for example, I have a “Reset” button that, when clicked, should restore the camera’s position to its initial state after the user has zoomed or panned), what would be the best approach to achieve this?
  1. If they have the MainCamera tag then yes. Otherwise not automatically. You can change the camera with this.context.setCurrentCamera(...) anytime
  2. Add a component to your camera, this one saves in start() or awake() e.g. this.originalPosition = this.gameObject.worldPosition.clone() and (if using with orbitcontrols) orbitControls.controls.target.clone() in a variable.
    Then add a reset() {...} method which you call from your Reset button onClick event and in that method you either call the OrbitControls methods OR directly set the gameObject’s worldPosition and worldQuaternion (this.gameObject.worldPosition = this.originalPosition;)

The issue I’m facing with moving the target is that the target is present in the source scene, and the child scenes have GameObject that depend on the target’s position. So, moving the target alone won’t work for me.

If I reload the scene, that should reset the camera, right?

I’m not sure I can follow unfortunately. Your child scene’s camera has an OrbitControls component - but you do want to reset this camera to your main scene’s camera position?