Преобразование 3D-положения в 2D-положение экрана [r69!]
Мне нужен код Three.js для преобразования координат трехмерных объектов в 2d в элементе 'div', чтобы я мог размещать текстовые метки там, где они должны быть (без масштабирования / перемещения / вращения этих меток вместе с движением 3D). К сожалению, все примеры, которые я видел и пробовал до сих пор, похоже, используют устаревшие функции / методы. В моем случае я считаю, что я использую r69 из Three.js.
Вот пример "старой" методики, которая просто выдает мне ошибки:
Three.js: преобразование 3d-позиции в 2D-позицию на экране
Вот фрагмент более нового кода (?), Который не предоставляет мне достаточного контекста для работы, но выглядит намного чище:
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
};
};