0
votes

I'm trying to get the grandchild of a rotated Object3D element to lookAt() the camera.

I've tried a lot of approaches. The source code of Three.js Object3D.lookAt() function specifically states that: // This method does not support objects with rotated and/or translated parent(s)

Which I understand as part of the rendering graph in the scene. I've tried copying the lookAt() code.

My structure goes like Object3D() [rotated] -> Object3d() -> Object3D() [text mesh I want to face 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 is just an example of what I've tried. Clearly my approach is all wrong. I'm thinking now that I'll need to keep the child objects in their own scene level container so they can relate to World space independently of the rotating parent.

Nothing actually happens to the text mesh (grandchild Object3D) rotation. It acts like nothing has been updated in this case. I checked the docs and still can't see why it's not even changing anything.

Thanks in advance for any help!

1

1 Answers

0
votes

You can use this function :

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

Use it on an object with a rotated parent like this : (check this fiddle)

alwaysLookAtCamera(anyObjectFromTheScene, camera);

Basically, it overrides the matrixWorld of a given object before rendering it.

However, I do not recommend to use this function as three.js was not built to be used like this.

Check WestLangley's answer for a proper solution