Determining a quaternion through the combination of two angles

I am currently working on a script that allows the THREE.js camera to rotate based on input from a mobile phone's gyroscope. While the functionality is mostly working fine, I have noticed an issue where the camera abruptly turns 180 degrees when crossing over into a new quadrant instead of smoothly continuing its rotation as intended. Here is the code snippet that I am using:

private onDeviceOrientation = ( event ) => {

  if( event.alpha !== null && event.beta !== null && event.gamma !== null ) {

    let rotation = [
      event.beta,
      event.alpha,
      event.gamma
    ],

    this.orientation = new THREE.Vector3(rotation[0], rotation[1], rotation[2]);
    this.viewer.navigation.setTarget(this.calcPosition());
  }
};

private calcPosition = () => {

    const camPosition = this.viewer.navigation.getPosition(),
          radians = Math.PI / 180,
          aAngle = radians * - this.orientation.y,
          bAngle = radians * + this.orientation.z,
          distance = this.calcDistance();

    let medianX = Math.cos(bAngle) * Math.sin(aAngle);
    let medianY = Math.cos(bAngle) * Math.cos(aAngle);

    let nX = camPosition.x + (medianX * distance),
        nY = camPosition.y + (medianY * distance),
        nZ = camPosition.z + Math.sin(bAngle) * distance;
    return new THREE.Vector3(nX, nY, nZ);
};

window.addEventListener('deviceorientation', this.onDeviceOrientation, false);

After some research, I realized that using Quaternions could potentially solve the issue of abrupt rotations when transitioning between quadrants. However, I have limited experience with Quaternions and would like some guidance on how to incorporate them into the current code with Vector3.

[Edit]

To calculate the distance, I use the following method:

private calcDistance = (): number => {
    const camPosition = this.viewer.navigation.getPosition();
    const curTarget = this.viewer.navigation.getTarget();
    let nX = camPosition.x - curTarget.x,
        nY = camPosition.y - curTarget.y,
        nZ = camPosition.z - curTarget.z;
    return Math.sqrt((nX * nX) + (nY * nY) + (nZ * nZ));
};

Furthermore, I adhere to the MDN conventions when handling gyroscope interactions.

[Edit #2] Upon correcting my angle calculations, I was able to resolve the issue by computing the final position in this manner:

let nX = camPosition.x - (Math.cos(zAngle) * Math.sin(yAngle)) * distance,
    nY = camPosition.y + (Math.cos(zAngle) * Math.cos(yAngle)) * distance,
    nZ = camPosition.z - (Math.cos(xAngle) * Math.sin(zAngle)) * distance;

Answer №1

Allow me to provide you with the most accurate response possible:

Before delving into the complexities of quaternions, let's establish that in your scenario, Euler angles are sufficient for representing orientation information. Avoiding Euler angles would be essential only if calculating angular velocities were involved due to potential infinity rates of change at certain orientations. Since this is not the case in your situation, there is no need to overcomplicate matters.

To address the issue you are facing, it seems clear that while you have the device's full orientation provided as yaw, pitch, and roll, translating this into camera control poses a challenge. The two axes related to where the camera points can be determined, but incorporating the roll component becomes ambiguous. As you attempt to output this data to the camera controller using Cartesian coordinates representing the target location, the disparity arises from the inability to accurately convey both roll direction and distance within the three outputs available.

If you opt for a fixed distance value for simplicity, despite any initial drift, it will eliminate unnecessary complexity and potential numerical instability stemming from recursive definitions. Consequently, the camera controller may default to zero degrees for the roll angle, resulting in discontinuities during maneuvers near zenith positions.

In such instances, incorporating the roll angle back into the displayed image could serve as a viable workaround. By rotating the image based on the desired rollout angle, derived possibly from 'beta,' adjustments can be made to align the display with the actual orientation of the device.

Given the absence of physical access to your system, detailed troubleshooting advice may prove challenging. Nonetheless, the key takeaways remain: you can bypass quaternion usage, maintain a fixed target distance, reintroduce the roll angle post-rotation, and embrace the journey towards achieving success in your endeavor!


Summary:

  • Quaternions are unnecessary
  • Opt for a fixed target distance
  • Incorporate roll angle into the displayed image via rotation
  • Best of luck!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

By implementing Async.parallel, I ensure that the lifetime of my parameter does not exceed the duration of the asynchronous calls in NodeJS when working with MongoDB

After analyzing the code and its asynchronous behavior, it appears that the 'recipeData' array may not persist long enough to handle the asynchronous callbacks. To mitigate this, I created a copy of the data in a global array. However, I am encou ...

Utilize CamelCase in jQuery for Better Code Readability

Upon examining the jQuery source code, I noticed an interesting use of camelcase: camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); } // where: rmsPrefix = /^-ms-/, rdashAlpha = /-([\da- ...

Having trouble getting the focus-within CSS pseudo-class to work with an HTML label

I'm attempting to create a dropdown menu with checkboxes inside the dropdown area. Below is the code snippet I am using: .search-box { color: black; width: 450px; } .search-box .fake-tb { display: flex; flex-wrap: nowrap; background: #f ...

A method to efficiently send multiple axios GET requests by incrementing the URL parameters

Is there a way to efficiently send multiple HTTP GET requests using Axios? For instance: let maxRequests = 3000; let currentRequest = 0; do { currentRequest = currentRequest + 1; await response = axios.get(`https://example.com/${currentRequest}` ...

What is the method for incorporating an async middleware into a router route?

I am currently setting up routes for an express router in my project. I have a validator that deals with promises, requiring me to use await in the code. Here is how it looks: constructor() { this.router = express.Router(); this.router.use(express. ...

`Property cannot be redefined: __internal__deprecationWarning` detected in a Shopify Hydrogen development project

Recently, while working on my Shopify Hydrogen project using Remix and Typescript, I encountered a sudden error when running npm run dev. Everything was functioning perfectly just 5 hours ago, but after returning from dinner, the app refuses to launch. ╭ ...

Can you explain the distinction between using this.function and making a function call in React?

I'm new to React and recently came across some code in a project that confused me. Could someone please clarify the distinction between this.function and the following function call used in a React event handling prop? <button onClick={this.clickH ...

Elasticsearch query fails to execute when encountering a special character not properly escaped

I am facing an issue with querying a keyword that includes a dot (.) at the end. While the query works perfectly on Kibana's console, it fails to execute on my application's function. The following function is responsible for creating the query b ...

Altering the parent component's output depending on a boolean value established in the child component within Angular

Recently I began learning Angular and find myself in need of some assistance when it comes to managing a specific situation with Angular 16. In our project, we have two different versions of the site header represented by two components - one as the defaul ...

Encountering an 'Module not found' error with three.js three-nodes

./node_modules/three/examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js Module not found: Unable to locate 'three-nodes/core/CodeNode.js'. I am working with react and trying to import three from node_modules, but it keeps throwing this erro ...

When using Vue.js, styling SVGs with CSS proves difficult as it applies inline styles in the DOM rather than using class names

Recently, I tried to update the appearance of some SVG images using CSS, but to my surprise, nothing changed. Upon inspecting the page, I noticed that the styles were located under the 'element.style' tag, which may explain why my attempts were u ...

What is the best way to trigger a 'Save As' dialog box on a browser when a button is activated within an Angular application, guaranteeing cross-browser compatibility?

The solution needs to be compatible with both Windows and Mac operating systems. Additionally, we should be able to specify a default file name and type. ...

What is preventing absolute paths from functioning properly in TurboRepo?

After setting up a fresh project on the most recent version of TurboRepo, I ventured into the 'apps' directory and established a new Vite project using the 'react-swc-ts' template. Making tweaks to the 'tsconfig.json' file wit ...

What is causing the chat-widget to display a null value for the style read property?

Could someone assist me with hiding the Widget-chat? I keep getting an error that the property of style is null. Any help would be greatly appreciated. Thank you in advance. document.getElementById("chat-widget").style.display='none'; ...

Cypress encounters a SyntaxError while running in continuous integration due to an unexpected token 'export' with the cypress-io/github-action@v2 typescript

Within my cypress plugin file located at frontend/cypress/plugins/index.ts, I have the following code snippet: export default ((on, config) => { // `on` is used to hook into various events Cypress emits // `config` is the resolved Cypress config }) ...

Pass data to JavaScript using Node.js Express server

I recently started learning nodejs and have encountered a challenge in sending a variable from my nodejs express server to a javascript file. The code I currently have is: res.send(String(playerLives)); The variable playerLives is an integer, and I faced ...

The following 13 error occurred in the node_modules/next/dist/esm/server/web/spec-extension/cookies/serialize.js file

Every time I try to use the serialize function in my application on Next, it throws errors. Error - node_modules/next/dist/esm/server/web/spec-extension/cookies/serialize.js (40:0) @ parseCookieString Error - URI malformed I have attempted numerous soluti ...

Exploring JSONPath in Cypress

I am currently working on extracting a JSON path for the specific HTML content with the language code DE Below is an example of the JSON data: { "name": "Name", "text": "", "html": "HTML content" ...

Utilize the event bus by calling `this.$root.$emit` command

I recently implemented a basic Event bus in my application to dynamically change styles on a page, and it's functioning correctly. The event bus is triggered using the $emit and $on methods as shown below: EventBus.$on and EventBus.$emit('call ...

Eslint problem: no-duplicates Fixing issue: cannot load resolver "node"

After performing an update on my project (a SPA using VueJS and Quasar Framework) today with npm update, I am encountering difficulties running it. An error message no-duplicates Resolve error: unable to load resolver "node" keeps appearing in various mod ...