Преобразование 3D-положения в 2D-положение экрана [r69!]

Мне нужен код Three.js для преобразования координат трехмерных объектов в 2d в элементе 'div', чтобы я мог размещать текстовые метки там, где они должны быть (без масштабирования / перемещения / вращения этих меток вместе с движением 3D). К сожалению, все примеры, которые я видел и пробовал до сих пор, похоже, используют устаревшие функции / методы. В моем случае я считаю, что я использую r69 из Three.js.

Вот пример "старой" методики, которая просто выдает мне ошибки:

Three.js: преобразование 3d-позиции в 2D-позицию на экране

Вот фрагмент более нового кода (?), Который не предоставляет мне достаточного контекста для работы, но выглядит намного чище:

https://github.com/mrdoob/three.js/issues/5533

4 ответа

Решение

Я написал для своего проекта следующую функцию; он получает THREE.Object3D экземпляр и камера в качестве параметров и возвращает положение на экране.

function toScreenPosition(obj, camera)
{
    var vector = new THREE.Vector3();

    var widthHalf = 0.5*renderer.context.canvas.width;
    var heightHalf = 0.5*renderer.context.canvas.height;

    obj.updateMatrixWorld();
    vector.setFromMatrixPosition(obj.matrixWorld);
    vector.project(camera);

    vector.x = ( vector.x * widthHalf ) + widthHalf;
    vector.y = - ( vector.y * heightHalf ) + heightHalf;

    return { 
        x: vector.x,
        y: vector.y
    };

};

Затем я создал THREE.Object3D просто для удержания позиции div (она прикреплена к сетке в сцене) и при необходимости ее можно легко преобразовать в положение экрана с помощью toScreenPosition функция и обновляет координаты элемента div.

var proj = toScreenPosition(divObj, camera);

divElem.style.left = proj.x + 'px';
divElem.style.top = proj.y + 'px';

Здесь скрипка с демо.

Вы можете преобразовать трехмерную позицию в экранные координаты, используя шаблон следующим образом:

var vector = new THREE.Vector3();
var canvas = renderer.domElement;

vector.set( 1, 2, 3 );

// map to normalized device coordinate (NDC) space
vector.project( camera );

// map to 2D screen space
vector.x = Math.round( (   vector.x + 1 ) * canvas.width  / 2 );
vector.y = Math.round( ( - vector.y + 1 ) * canvas.height / 2 );
vector.z = 0;

Three.JS R.69

Для меня эта функция работает (Three.js версия 69):

function createVector(x, y, z, camera, width, height) {
        var p = new THREE.Vector3(x, y, z);
        var vector = p.project(camera);

        vector.x = (vector.x + 1) / 2 * width;
        vector.y = -(vector.y - 1) / 2 * height;

        return vector;
    }

Это дополнительный код к ответу @meirm, где .getContext() используется в последней версии THREE.js и добавляется смещение холста, потому что иногда холст встроен в другой пользовательский интерфейс.

      const toScreenPosition = function(obj, camera){
    let vector = new THREE.Vector3();
    let widthHalf = 0.5 * renderer.getContext().canvas.width;
    let heightHalf = 0.5 * renderer.getContext().canvas.height;
    obj.updateMatrixWorld();
    vector.setFromMatrixPosition(obj.matrixWorld);
    vector.project(camera);
    vector.x = ( vector.x * widthHalf ) + widthHalf + $(scenecanvas).offset().left;
    vector.y = - ( vector.y * heightHalf ) + heightHalf + $(scenecanvas).offset().top;
    return { 
        x: vector.x,
        y: vector.y
    };
};
Другие вопросы по тегам