Slerping with quaternions in Three.js can produce undesirable outcomes when near the poles

Check out this video example: https://drive.google.com/file/d/18Ep4i1JMs7QvW9m-3U4oyQ4sM0CfIFzP/view

In the demonstration, I showcase how I determine the world position of a ray hitting a globe under the mouse cursor. By utilizing lookAt() with a THREE.Group, I am able to obtain a quaternion with the correct rotation. The red dot constantly underneath my mouse demonstrates the accuracy of this quaternion. Subsequently, starting from the quaternion representing the center of a large yellow dome, I employ rotateTowards towards the quaternion of the mouse position (red dot) and assign this resulting quaternion as the rotation for the blue dot that follows the mouse. This method is intended to ensure the blue dot always remains attached to the dome when the mouse is further away. While it functions correctly nearer to the southern hemisphere, issues arise near the north pole where the calculation deviates from the expected great circle.

Here is the relevant code snippet:

// Using hammerjs pan events, I send an event containing the position on the sphere under the mouse to the blue sphere.
// 'event.point' value is accurate, validated by the red sphere constantly under the mouse.

this.helperGroup.lookAt(event.point); // Obtain required rotation
const p = this.helperGroup.quaternion.clone(); 

// 'p' represents a rotation toward the point under the mouse
const requestedDistance = dome.quaternion.angleTo(p);

if (allowedDistance >= requestedDistance) {
    blueSphere.parent.lookAt(event.point);
} else {
    blueSphere.parent.quaternion.copy(
        dome.quaternion.clone().rotateTowards(p, allowedAngle)
    );
}

//  This snippet has been modified for illustrative purposes.

Update and alternative approach:

Originally, I relied on lookAt() and rotation-based techniques to minimize mathematical complexity. However, I have now transitioned to using cartesian coordinates, normal vectors, and axis-based rotations for greater precision. Contrary to my initial belief, embracing math has proven to simplify the process significantly.

const requestedDistance = blueSphere.angleTo(event.point);
let norm = dome.position.clone().cross(event.point).normalize();
if (allowedDistance >= requestedDistance) {
    blueSphere.position.set(event.point); 
} else {
    blueSphere.position.set(dome.position.clone()
                            .applyAxisAngle(norm, allowedAngle);
}

Answer №1

A singularity close to the poles is inherent in the quaternion slerp function; it cannot be circumvented unless a different method is utilized. In his piece titled "Understanding Slerp, Then Not Using It", Jonathan Blow delves into the complications of the slerp function and proposes that utilizing an alternative approach such as normalized lerp or nlerp might be more favorable in most cases.

It is worth noting that even the C++ code for slerp mentioned in the article recognizes the existence of a singularity within the slerp function.

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

Develop a personalized mapping API with a unique image integration for website navigation

Currently, I am in the process of developing a website for my university that will allow users to easily locate all available free food options on campus. My goal is to create a platform where food providers can register their events, have them saved in a ...

When I click a button in d3 to refresh the data on my bar graph, the text fails to update accordingly

I've successfully created a series of data lists that modify the bargraph. Unfortunately, due to their differing x and y values, they end up printing new values on top of existing ones. Shown below is an image illustrating the issue where x and y val ...

What is the best way to organize JSON models in THREE.js?

I've encountered an issue while trying to group loaded JSON models in THREE.js... THREE.Object3D.add: object not an instance of THREE.Object3D The problem arises when I use the following example code... var group = new THREE.Object3D(); and then a ...

Creating an interactive table with the power of FPDF and PHP

I have developed a unique Invoice System that allows users to customize the number of headings and fields using FPDF in conjunction with PHP. Subsequently, I can input the heading names and field values into HTML input fields. However, I am encountering a ...

What are the steps to modify the authorization header of an HTTP GET request sent from a hyperlink <a href> element?

I have a unique Angular application that securely saves JWT tokens in localstorage for authentication purposes. Now, I am eager to explore how to extract this JWT token and embed it into an HTTP GET request that opens up as a fresh web page instead of disp ...

What is the reason behind the blocking of Ajax GET requests without CORS, while JSONP requests are permitted?

Accessing any page on the web through a GET request using HTML tags from a different origin is possible: <script src="http://example.com/user/post?txt=sample"></script> XHR requests to other origins are blocked for security reasons. For examp ...

Is there a way to accurately retrieve the width of an element within setInterval without any delay?

I'm currently experimenting with increasing a progress bar using the setInterval function. So far, it seems to be functioning properly. var progressBar = $('.progress-bar'); var count = 0; var interval = setInterval(function () { va ...

Transfer the chosen language from the uib-dropdown language selector to the $scope variable

Here is a HTML template that allows the user to select a language: <div class="btn-group" uib-dropdown> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" uib-dropdown-toggle> ...

Despite mutating the state, the Redux reducer does not trigger a rerender on my React Component

Lately, I've been facing challenges with redux as it sometimes doesn't trigger the rerendering of my React components. I understand that I need to update the state in order for Redux to detect changes. However, even after doing so, my React Compo ...

transferring various data from JavaScript page to PHP page

Is it possible to pass multiple values from a service page to a PHP page? I am trying to pass the values 'data', 'albimg' and 'albvideo' to the PHP page, but I keep encountering an error. Please refer to the image below for mo ...

I'm running into an InvalidSelectorError and I could use some assistance in properly defining

As I gaze upon a massive dom tree, my task using NodeJS/Selenium is to locate an element by the title attribute within an anchor tag and then click on the associated href. Despite being a newcomer to regex, I am encountering numerous errors already. Below ...

Angular 4 - Automatically scroll to specific list item based on search query input

While I can achieve this with custom JavaScript, I'm curious if Angular 4 has any built-in features that could help. I have a list of checkboxes that are scrollable and a search input above them. My goal is to enable users to quickly jump to a section ...

InvalidTypeError: The function 'state.map' cannot be applied

import React from "react"; import { useContext, useEffect, useRef, useState } from "react"; import noteContext from "../Context/notes/NoteContext"; import Addnote from "./Addnote"; import Noteitems from "./Notei ...

Exploring elements with Watir WebDriver and ExtJS

Currently, I am performing an acceptance test using watir-webdriver with Ruby. I have a question regarding ExtJs support with Watir webdriver. Is it possible to locate elements that are dynamically generated by ExtJS? I have attempted the following: @brow ...

How can I effectively separate the impact of Next.js onChange from my onClick function?

The buttons in my code are not functioning properly unless I remove the onChange. Adding () to my functions inside onClick causes them to run on every keystroke. How can I resolve this issue? In order to post my question, I need to include some dummy text. ...

Exploring the power of VueJs through chaining actions and promises

Within my component, I have two actions set to trigger upon mounting. These actions individually fetch data from the backend and require calling mutations. The issue arises when the second mutation is dependent on the result of the first call. It's cr ...

Is there a way to modify the color of a specific section of a font icon?

Currently, I am in the process of implementing an upvote button using fa fa signs. However, I have encountered an issue where the background color of the up vote button is bleeding outside of the sign (possibly due to padding on the icon), and I am strivin ...

Creating an Eye-Catching Tumblr Landing Page

As I work on Tumblr, my goal is to create a landing page that features an "Enter" button directing users to the home page. After some research, I came across a code snippet that redirects the site to a /welcome page when placed in the index page. <scri ...

Troubleshooting IE Freezing Issue Due to JavaScript Code with .addClass and .removeClass

Need some help troubleshooting why my code is causing IE to crash. After commenting out sections, I discovered that the issue arises when using .addClass and/or .removeClass inside the if conditions: if ( percentExpenses > 50 && percentExpenses ...

Newbie's guide: Saving information in Ruby on Rails

In my Rails 4 application, I am looking to save questions and answers either in a document or database. Once stored, I want to showcase them on a specific webpage for users to respond. For instance, I envision having a page titled /questions where a quest ...