Updating the rotation of a grandchild in Three.js Object3D

In my current project, I am attempting to make the grandchild of a rotated Object3D element face towards the camera using the lookAt() method.

I have experimented with various approaches to achieve this. However, the source code for the Object3D.lookAt() function in Three.js clearly mentions:

// This method does not support objects with rotated and/or translated parent(s)

From my understanding, this limitation is related to the hierarchy of objects in the rendering graph within the scene. Despite trying to replicate the logic of the lookAt() function, I have not been successful.

The structure of my objects is as follows: Object3D() [rotated] -> Object3d() -> Object3D() [text mesh that I want to align with the camera in each frame]

lookAt(textObject, artistProps) {
    let m1 = textObject.matrixWorld.clone();
    textObject.matrixAutoUpdate = false;
    m1.lookAt(textObject.localToWorld(textObject.position), Props.camera.position, THREE.Object3D.DefaultUp);
    textObject.quaternion.setFromRotationMatrix(m1);
    textObject.matrixWorld.makeRotationFromQuaternion(textObject.quaternion);
    textObject.matrixWorldNeedsUpdate = true;
    textObject.updateMatrixWorld();
}

This code snippet represents one of my attempted solutions. It seems that my approach may be flawed. My current thinking is leaning towards isolating the child objects into their own container at the scene level so they can maintain their relationship with World space independently from the rotating parent.

Unfortunately, despite these efforts, the rotation of the text mesh (grandchild Object3D) remains unchanged. It almost appears as though no updates are taking effect. Even after consulting the documentation, I am unable to pinpoint the issue.

I would greatly appreciate any assistance on this matter. Thank you in advance!

Answer №1

If you're looking to make an object always face the camera, try using this JavaScript function:

var keepFacingCamera = function () {
    var worldPosition = new THREE.Vector3();
    if (+THREE.REVISION > 85) {
        return function (targetObject, camera) {
            targetObject.onBeforeRender = function() {
                worldPosition.setFromMatrixPosition(targetObject.matrixWorld);
                targetObject.matrixWorld.lookAt(camera.position, worldPosition, THREE.Object3D.DefaultUp);
                targetObject.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, targetObject.matrixWorld);
                targetObject.normalMatrix.getNormalMatrix(targetObject.modelViewMatrix);
            };
        };
    } else {
        return function (targetObject, camera) {
            targetObject.onBeforeRender = function() {
                worldPosition.setFromMatrixPosition(targetObject.matrixWorld);
                targetObject.matrixWorld.lookAt(camera.position, worldPosition, THREE.Object3D.DefaultUp);
            };
        }
    }
}();

Apply it to an object with a rotated parent by calling it like this: (see this example)

keepFacingCamera(someObjectInScene, camera);

This function adjusts the matrixWorld of the object prior to rendering.

Keep in mind that while this workaround may work, it's not the recommended approach as three.js wasn't designed for this use case.

For a more appropriate solution, refer to WestLangley's response.

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

Error: Kinetic.js cannot upload image to canvas

There must be something simple that I'm missing here. I've checked my code line by line, but for some reason, the image just won't load. var displayImage = function(){ var stage = new Kinetic.Stage("imgarea", 250, 256); var layer = new ...

Adjusting the filter location in React-admin

This is the common method of implementing filters in react-admin https://i.stack.imgur.com/M8yq7.png However, in my particular scenario, I require the filters to be inside each column heading. For example: https://i.stack.imgur.com/GU2Pz.png The filter ...

I'm looking to display 9 images on a single page that rotate every 5 seconds between 3 different images. While I can figure out how to display one image easily, I'm

<script type="text/javascript"> var currPic = 1; var totPics = 9; var keepTime; function setupPicChange() { keepTime = setTimeout("changePic()", 5000); } function changePic() { currPic++; if (currPic > totPics) currPic = 1; var f ...

Orbit Control is experiencing issues with initialization

I'm attempting to create a three.js STL model viewer using code. Here is the code snippet: <!-- prerenderer --> <!doctype html> <html> <head> <title>Enjoy your model</title> <meta charse ...

Looking to showcase elements within an array inside an object using ng-repeat

In this JSON dataset, we have information about various anchoring products. These products include anchors, cleats, snubbers, shackles, and more. When it comes to displaying these products on an HTML page using Angular, make sure to properly reference the ...

Imported Three.js objects with varying initial positions

I'm encountering an issue with Three.js as a newcomer. I've successfully imported an external 3D object with the .obj extension and added it to my scene. My goal is to position this newly imported object at (0, 0, 0) coordinates. To achieve this, ...

Step-by-step guide for setting up chartjs on Laravel 6 using npm

Can anyone guide me on how to properly install and integrate [email protected] in my laravel application? Currently, I am using cdn links, but I want to avoid that in the future. List of cdn links being used: <script src="https://cdnjs.c ...

What is the method for setting a function as the initial value of a state variable?

Here is a function I have: async function setAllValues(value) { await stableSort(rows, getComparator(order, orderBy)) .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) .forEach((row) => { temp = ...

What is the best way to activate multiple events within an overlapping area containing multiple divs at the same

How can I trigger events on same level divs that overlap in different areas? When there are multiple divs overlapping, only one of them gets triggered. Is there a way to trigger events on all overlapped same level divs? Here is an example code snippet: ...

Arranging an Array of Arrays Containing Strings

Looking for a solution to sort an array containing arrays of strings? A similar issue was discussed here. Here is the array in question: var myArray = [ ['blala', 'alfred', '...'], ['jfkdj', ...

The Distinction Between "Q" and "q" in AngularJS and RequireJS

Currently, my project involves developing a single page application using AngularJS, Breeze, and RequireJS. While trying to configure AMD with requirejs to integrate Angular and Breeze, I ran into an issue related to Breeze's dependency on "q". Intere ...

Array of JSON data passed in the request body

Recently, I have been attempting to pass JSON data to my req.body. The data structure is as follows: answers = ["A","B"]; //An array to be included in the JSON Object var Student_Answers = { //JSON object definition Answers: answers, matricNumber: ...

Tips for customizing Material-UI Switch button appearance

Is there a way to remove the box-shadow on the thumb of the Switch button when it's disabled? I've tried various methods like adding the box-shadow in the switchBase and removing it from the thumb, but it affects the parent element as well. Anoth ...

Ensuring that the initial column of a table remains in place while scrolling horizontally

Thank you for taking the time to read this. I am currently working on a table within a div container (div0) where the data is dynamically generated, resulting in a table with unpredictable height and width. The outer div allows for both vertical and horizo ...

How can you display a doughnut chart with a custom color to represent empty or no data, including doughnut rings?

I have integrated a doughnut chart from chartjs into my Vue project using vue-chartjs. Currently, the doughnut chart does not display anything when there is no data or all values are empty. Is there a way to customize the color and show the entire doughnu ...

Submit numerous queries to verify the presence of a name and assign it to the name attribute

I have a collection of unique devices. As part of a process, I need to assign a default name to each device ("DeviceX" - where X is a sequential number), but some of the names may already be in use. To handle this, I must make a request to check ...

Is there a method to modify the arrangement in which 3 specific HTML elements are displayed (i.e., their hierarchy in relation to one another)?

I have 3 "p" elements and I'm trying to find a way to change the order in which they load on the page using JS or CSS. Below is an example of what I've attempted so far. When you click on the first box labeled "about 1," it opens up and displays ...

Overwriting the responseText from a previous XMLHttpRequest in JavaScript

I am working on updating two different JavaScript charts displayed on a PHP page by making sequential XMLHttpRequests using JavaScript. The goal is to update the data on these charts simultaneously. <!DOCTYPE HTML> <html> <head> <scri ...

The error message "Vue.JS computed from VueX Store is not recognized" is displaying

Within my Vuex store, I am able to see it in the Vue Devtools tool. However, when attempting to load data into a computed property, an error message stating that it is not defined is displayed. computed: { userData(){ return this.$store.state.use ...

To iterate through a multi-dimensional array

I am facing an issue with fetching data within an array in the code below var str = "Service1|USER_ID, Service1|PASSWORD" var str_array = str.split(','); console.log(str_array) for(var i = 0; i < str_array.length; i++) { str_array[i] = st ...