将 3D 位置转换为 2D 屏幕位置 [r69!]

问题描述 投票:0回答:4

我需要 Three.js 代码将 3D 对象坐标转换为“div”元素中的 2D 坐标,以便我可以将文本标签放置在需要的位置(这些标签不会随着 3D 运动而缩放/移动/旋转)。不幸的是,到目前为止我所看到和尝试过的所有示例似乎都在使用过时的函数/技术。就我而言,我相信我正在使用 Three.js 的 r69。

这是一个“旧”技术的示例,它只会给我带来错误:

Three.js:将 3d 位置转换为 2d 屏幕位置

这是一些较新代码的片段(?),它没有为我提供足够的上下文来开始工作,但看起来更干净:

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

javascript three.js 3d 2d coordinates
4个回答
50
投票

我为我的项目编写了以下函数;它接收

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';

这里有一个演示


30
投票

您可以使用如下模式将 3D 位置转换为屏幕坐标:

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;

三.js r.69


8
投票

对我来说这个函数有效(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;
    }


1
投票

这是 @meirm 答案的补充代码,其中 .getContext() 在最新版本的 THREE.js 中使用,并且添加了画布的偏移量,因为有时画布嵌入到另一个 UI 中。

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
    };
};
© www.soinside.com 2019 - 2024. All rights reserved.