Matrix calculation for bone orientation towards an object in Three.js

I am encountering issues with calculating the orientation of a bone to "look at" an object. The lookAt function is not functioning as expected for me. This could be due to the fact that the bone's matrix is an identity matrix in local space, so the default behavior does not align correctly (resulting in strange outcomes).

So far, I have managed to rotate the head from left to right, but I have not yet figured out the calculation for up and down movement. Unfortunately, the current implementation is not working well at the moment :(

    // Define local forward vector
    var v1 = new THREE.Vector3(0, 0, 1);
    // Vector representing the camera in local space
    var v2 = new THREE.Vector3(
        camera.position.x - headBone.matrixWorld.elements[12], 
        0, 
        camera.position.z - headBone.matrixWorld.elements[14]
    );
    v2.normalize();
    // Determine whether to rotate left or right
    var mult = 1.0;
    if(camera.position.x - headBone.matrixWorld.elements[12] < 0.0000) {
        mult = -1.0;
    }
    var fAng = v1.angleTo(v2) * mult;
    // Rotate the head bone left or right
    headBone.quaternion.setFromAxisAngle(new THREE.Vector3(0,0,-1), fAng);

I am open to any suggestions on how to achieve this calculation correctly since I am currently struggling with the math. In the meantime, I will continue troubleshooting...

If it helps, here is the worldMatrix of the headBone in its original position:

 0.9950730800628662,      -0.02474924363195896,   0.09600517153739929,   0
-0.09914379566907883,     -0.2472541183233261,    0.9638656973838806,    0
-0.00011727288801921532,  -0.9686352014541626,   -0.24848966300487518,   0
 0.5000047087669373,       1.5461946725845337,   -0.01913299970328808,   1

UPDATE

After updating my code, I have made progress in rotating the head bone on different axes (x and z) to align with the camera. However, when I try to combine these rotations, the orientation goes haywire especially when at the sides of the character, causing the head to spin uncontrollably.

function lookAt() {
    var v1 = new THREE.Vector3(0, 0, 1);
    var v2 = new THREE.Vector3(
        camera.position.x - headBone.matrixWorld.elements[12], 
        0, 
        camera.position.z - headBone.matrixWorld.elements[14]
    ).normalize();
    var mult = 1.0;
    if(camera.position.x - headBone.matrixWorld.elements[12] < 0.0000) {
        mult = -1.0;
    }
    var fAng = v2.angleTo(v1) * mult;

    v2 = new THREE.Vector3(
        0, 
        camera.position.y - headBone.matrixWorld.elements[13], 
        camera.position.z - headBone.matrixWorld.elements[14]
    );
    mult = 1.0;
    if(camera.position.y - headBone.matrixWorld.elements[13] > 0.0000) {
        mult = -1.0;
    }
    fAng2 = v2.angleTo(v1) * mult;
    headBone.rotation.set(
        Math.max(-0.5, Math.min(fAng2, 0.1)), 
        0, 
        -Math.max(-1.0, Math.min(fAng, 1.0))
    );

} 

I have attempted to use separate quaternions for individual rotations:

    // Rotate head left and right to match camera
    var Q1 = new THREE.Quaternion().setFromEuler( new THREE.Euler(0,0,-fAng), false );
    // Rotate head up and down to match camera
    var Q2 = new THREE.Quaternion().setFromEuler( new THREE.Euler(fAng2,0,0), false );
    Q2.multiply(Q1);
    headBone.quaternion.copy(Q2);

However, this solution still does not accurately track the camera. It is worth noting that applying either rotation individually works fine.

Answer №1

I have successfully found a solution that allows the bone to gaze towards any given point. I believe that this method has potential to be integrated into THREE.js for further development.

Despite its promising aspects, there are still some issues present which prevent it from being 100% accurate. One particular problem I have encountered is that when the bone is positioned on the head and the character points backwards, it ends up upside down. I am open to suggestions on how this can be improved, so please feel free to share your thoughts!

It's worth mentioning that I have set the bone's Z axis to THREE.Vector3(0,0,1); but this could potentially be made customizable through a parameter.

function boneLookAt(bone, position) {
        var target = new THREE.Vector3(
                position.x - bone.matrixWorld.elements[12],
                position.y - bone.matrixWorld.elements[13],
                position.z - bone.matrixWorld.elements[14]
        ).normalize();
    var v = new THREE.Vector3(0,0,1);
        var q = new THREE.Quaternion().setFromUnitVectors( v, target );
        var tmp = q.z;
        q.z = -q.y;
        q.y = tmp;
    bone.quaternion.copy(q);
}

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

My middleware produces different results when used by Postman compared to when used by a Browser

Recently, I began delving into backend development using Node.js and Express. One of the tasks I wanted to accomplish was creating a middleware that would display a message in the console if a request was made to a route that doesn't exist. Here is wh ...

Incorporate Add to Homescreen functionality into your Angular 4 Project using JavaScript

Currently I am in the beginning stages of learning Angular development. One of my assignments involves integrating the add to homescreen jQuery plugin into one of my pages. This is my attempt at implementing it in my home.component.ts file: ngAfterViewIn ...

Transferring data from a text area to a table with AngularJS

Creating a C# MVC App with AngularJS My goal is to populate a table with values entered in a text area using Angular. Here is the process: Users input values into a text area like this: A B C When a user clicks a button, a modal window should open and ...

The location of the CHROMEDRIVER for Node.js with Selenium

After trying "npm install selenium-webdriver", I am still encountering the error message below. Can anyone provide guidance on where the path is supposed to be located? Error: The ChromeDriver could not be found on the current PATH. Please download the ...

How to add 1 to the final element in a JavaScript

I'm currently working on a task that involves incrementing the last element in an array using pop() and push(). However, I'm facing an issue where the original values are being retained after I try to increment the popped array. The objective is ...

What is the best way to transfer the search query to a table filter when working with multiple JavaScript files?

I am struggling with passing the search query from my search file to my table file. The data for my datagrid table is retrieved from a database using an API call, and the table code is in one file while the search functionality code is in another file. I h ...

NextJs redirection techniquesWould you like to learn the best ways

Currently, I am developing an application using NextJS with Firebase authentication integration. Upon successful authentication, my goal is to retrieve additional customer details stored in a MongoDB database or create a new document for the customer upon ...

Utilizing Vue CLI's sourcemaps to pinpoint the styling within a Vue component file

Currently, I am working on a Vue CLI project. After setting up the project and making some development changes, my package.json file now includes: package.json "dependencies": { "bootstrap": "^4.3.1", "core-js": "^3.0.1", "preload-it": "^1.2. ...

retrieving the webpage's HTML content from the specified URL using AngularJS

Utilizing the $http.get('url') method to fetch the content located at the specified 'url'. Below is the HTML code present in the 'url': <html> <head></head> <body> <pre style = "word-wrap: break ...

What could be causing my fetch() function to send a JSON body that is empty?

I've been struggling with sending JSON data using fetch as the backend keeps receiving an empty object. In my Client JS code, I have the following: const user = "company1"; const username = "muneeb"; const data = {user, username}; fetch("http://127. ...

Comparison between HighChart, D3.Chart, and C3.Chart

In need of charting capabilities for my CMS Application. I am interested in incorporating Pie Charts, Area Charts, Column Charts, Bar Charts, and Gauge Charts. After doing some research online, C3.js and HighCharts.js stood out to me as promising options. ...

Issues encountered when updating values in MaterialUI's TextField using Formik

Within my React functional component, I utilize Formik for form management and MaterialUI V5.10 for styling. The form includes TextField elements and a Canvas element. I am encountering two issues... Despite setting initial values in Formik, the TextFiel ...

What could be causing the repetition of the same cookie in my request header when using jQuery ajax?

Stuck in a dilemma for hours now, seeking assistance or suggestions from anyone who can help me out. To sum it up, I have an asp.net web api application where I am trying to fetch data from a web api and populate multiple dropdown lists on a page using jQ ...

Navigate to an element with a specific ID using JavaScript

How can I implement scrolling to an element on a webpage using pure javascript in VueJS with Vuetify framework? I want to achieve the same functionality as <a href="#link"></a> but without using jQuery. My navigation structure is as follows: ...

Displaying retrieved data following AJAX request in ASP.NET MVC is currently not functioning

I have a situation where I need to populate two <p> fields with text Below is the HTML code snippet: <p id="appId" style="visibility: hidden;"></p> <p id="calculationId" style="visibility: hidden;"></p> I am making an AJAX ...

Tips for incorporating flow and TypeScript typings into an NPM module

Are there any resources available for adding both flow and typescript typings to an NPM module at the same time? I've been struggling to find a comprehensive guide on this topic, and it seems to be a common issue faced by open source library maintain ...

Issues arise when utilizing external scripts alongside <Link> components in ReactJS, resulting in them becoming unresponsive

I'm experiencing some difficulties with an external script when using <Link to="/">. The script is included in the main layout file index.js as componentDidMount () { const tripadvisorLeft = document.createElement("script"); tripadvisorLef ...

How is the purpose of nesting functions within functions achieved in nodejs?

Take a look at this example: var tools1 = require('../tools/tools1'); var test_func = function(arg1, arg2, arg3) { var local_var_1 = "lc1"; var local_var_2 = "lc2"; return function(data) { var result = tools1.doSth(local_va ...

Error: Unable to retrieve data due to null value (property 'detail' is undefined)

When I use useEffect() function to set the document title to 'View Orders | Bothub' and fetch data from a backend URL, I encounter an error. The error message reads: Unhandled Rejection (TypeError): Cannot read properties of null (reading 'd ...

Utilizing a JavaScript variable in a separate file: A guide

I am facing a JavaScript challenge where I have a variable that changes its value on a particular event. Now, I need to access this variable in a different file for some calculations. For instance, in my index.php file, I have the following variable: ...