How to get the real position on 'screen(top, left)' of a child of a 3D object?

Hello

Now I am going to get a screen coordinates of a child mesh of an Object.
e.g. I have a car model and I want to mark the position of engine using a red dot on the screen.
I tried above functions but it doesn’t work correctly. It points wrong position.

function toScreenPosition(obj, camera) {
            var vector = new THREE.Vector3().clone();
            var width = renderer.domElement.width;
            var height = renderer.domElement.height;
            // obj.updateMatrixWorld();
            // vector.setFromMatrixPosition(obj.matrixWorld);
            // vector.project(camera);
            // const aabb = new THREE.Box3().setFromObject(obj);
            // const center = aabb.getCenter(new THREE.Vector3());
            // console.log('center', vector);

            // vector.x = (center.x * widthHalf) + widthHalf;
            // vector.y = - (center.y * heightHalf) + heightHalf;
            // vector.x = (vector.x + 1) * widthHalf;
            // vector.y = - (vector.y - 1) * heightHalf;
            // vector.z = 0;

            // var geometry = obj.geometry;
            // geometry.computeBoundingBox();
            // var center = new THREE.Vector3();
            // geometry.boundingBox.getCenter(center);
            // obj.localToWorld(center);

            // var vector = new THREE.Vector3();
            // vector.setFromMatrixPosition(obj.matrixWorld);
            // vector.project(camera);

            // console.log('vector', vector);

            // vector.x = (vector.x * widthHalf) + widthHalf;
            // vector.y = - (vector.y * heightHalf) + heightHalf;
            // vector.z = 0;
            vector.setFromMatrixPosition(obj.matrixWorld).clone();
            vector.project(camera);

            var percX = (vector.x + 1) / 2;
            var percY = (-vector.y + 1) / 2;

            var left = percX * width;
            var top = percY * height;

            return {
                x: left,
                y: top
            };

        };
object.traverse(function (child) {
                        if (child.isMesh) {
                            if (child.name === 'engines') {
                                const btn = document.createElement('button');
                                btn.className = "btn-mark";
                                btn.id = child.name;
                                mark_btns.push({
                                    object: child,
                                    btn: btn,
                                })
                                container.appendChild(btn);
                            }
                        }
                    });

How can I implement this?

In general, you need to transform the 3d world position into 3d camera space and then into 2d screen space.

I haven’t used them in three, but check the examples and source code for Vector3.project and CSS2DRenderer

Hi, @ccammack Thank you for your reply. I have tried as the example and here is my code.
But it doesn’t work. Can you please have a look my code? What’s wrong on my code?

labelRenderer = new CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.zIndex = '-1';
container.appendChild(labelRenderer.domElement);
var loader = new GLTFLoader();

loader.setPath('packages/model/car/').load(model_name, function (gltf) {
    let object = gltf.scene;
    importFBX = object;
    object.scale.set(100, 100, 100);
    object.traverse(function (child) {
        if (child.isMesh) {
            child.castShadow = true;
            if (child.name === "engine") {
                const btnDiv = document.createElement('button');
                btnDiv.className = "btn-mark";
                btnDiv.id = child.name;
                const btnLabel = new CSS2DObject(btnDiv);
                btnLabel.position.copy(child.position);
                btnLabel.layers.set(0);
                child.add(btnLabel);
            }
        }
    });
    scene.add(object);
});

Thanks in advance!

Create a separate test project, starting with one of the working label examples, and then convert it into what you want by replacing the demo model with your car, and so on. Test it after every change to make sure you understand what each change does. Use the debugger to make sure the values look right and that you understand what the code is doing. If you’re still stuck after that, create a minimal demo on one of the code sharing sites like https://codesandbox.io/ or https://jsfiddle.net/ or https://codepen.io/ and ask for help here again.