Please check out the gist I put together over at
https://gist.github.com/sparkbuzz/f1f8d0d8bbc7757b679f
In this gist, you'll find a TypeScript class named OrbitControls. I've been delving into 3D and three.js to explore creating orbit-style controls. Drawing inspiration from MrDoob's JS OrbitControls, I have managed to create my version of these controls.
My implementation involves utilizing the mousedown, mousemove, and mouseup events to maneuver a camera around the world origin. Upon receiving the mousedown event, the initial position of the camera is captured using the following code snippet:
this.subjectPositionStart = this.subject.getWorldPosition();
This initial position serves as the reference for calculating the angles required to adjust the camera's position during a mousemove event when the mouse is moved across the canvas.
Throughout the mousemove event, calculations are performed to determine theta and phi angles based on the distance covered by the mouse. These values are then used to reposition the camera as follows:
this.subject.position.x = rho * Math.cos(theta) * Math.sin(phi);
this.subject.position.y = rho * Math.sin(theta) * Math.sin(phi);
this.subject.position.z = rho * Math.cos(phi);
While everything functions correctly, an issue arises when the rotation angle around the z-axis exceeds 90° or drops below -90° during the subsequent mousedown. In such cases, the camera position appears mirrored instead of aligning as intended.
The observed behavior indicates that the camera flips upon surpassing the 90° limit, resulting in its orientation being reversed although the degrees remain accurate.
As long as the 90° threshold isn't crossed, the navigation operates smoothly during the next mousedown, indicating that the problem lies within the mousedown handler function. When only mousemove events occur, there are no issues with exceeding the angle limits, and navigation proceeds without any hindrances.
Any insights on identifying the root cause of this anomaly?
UPDATE:
I suspect that my method of calculating baseTheta may be incorrect:
var baseTheta:number = Math.asin(this.subjectPositionStart.y / rho / Math.sin(basePhi));
After attempting the following calculation:
var baseTheta:number = Math.acos(this.subjectPositionStart.x / rho / Math.sin(basePhi));
The same issue persists, where the flip occurs between 180° and 360°. This recurring pattern suggests there might be a crucial clue hidden within...