使用投影将 Three.js 中的世界坐标转换为屏幕坐标

IT技术 javascript 3d three.js
2021-01-30 07:28:47

有几个关于 Three.js 中取消投影的优秀堆栈问题 ( 1 , 2 ),即如何将浏览器中的 (x,y) 鼠标坐标转换为 Three.js 画布空间中的 (x,y,z) 坐标。大多数情况下,他们遵循以下模式:

    var elem = renderer.domElement, 
        boundingRect = elem.getBoundingClientRect(),
        x = (event.clientX - boundingRect.left) * (elem.width / boundingRect.width),
        y = (event.clientY - boundingRect.top) * (elem.height / boundingRect.height);

    var vector = new THREE.Vector3( 
        ( x / WIDTH ) * 2 - 1, 
        - ( y / HEIGHT ) * 2 + 1, 
        0.5 
    );

    projector.unprojectVector( vector, camera );
    var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
    var intersects = ray.intersectObjects( scene.children );

我一直试图做相反的事情 - 而不是从“屏幕到世界”空间,而是从“世界到屏幕”空间。如果我知道 Three.js 中对象的位置,我如何确定它在屏幕上的位置?

这个问题似乎没有任何已发布的解决方案。关于这个的另一个问题刚刚出现在 Stack 上,但作者声称已经用一个对我不起作用的函数解决了这个问题。他们的解决方案不使用投影射线,我很确定由于 2D 到 3D 使用 unprojectVector(),因此 3D 到 2D 解决方案将需要 projectVector()。

Github上也有这个问题

任何帮助表示赞赏。

3个回答

试试这个:

var width = 640, height = 480;
var widthHalf = width / 2, heightHalf = height / 2;

var vector = new THREE.Vector3();
var projector = new THREE.Projector();
projector.projectVector( vector.setFromMatrixPosition( object.matrixWorld ), camera );

vector.x = ( vector.x * widthHalf ) + widthHalf;
vector.y = - ( vector.y * heightHalf ) + heightHalf;
更新了答案。谢谢@imbrizi!
2021-03-19 07:28:47
我认为您的代码在 getPositionFromMatrix 之前缺少向量。所以 vector.getPositionFromMatrix
2021-03-24 07:28:47
再次固定。对于那个很抱歉。
2021-03-29 07:28:47
getPosition() 已被弃用。改用这个: var vector =projector.projectVector(new THREE.Vector3().getPositionFromMatrix(object.matrixWorld), camera);
2021-03-30 07:28:47
另一个堆栈问题的操作发布了此链接,该链接也有解决方案。再次感谢!github.com/mrdoob/three.js/issues/78
2021-04-01 07:28:47

对于现代 Three.js (r75),可以使用以下命令将向量投影到屏幕上:

var width = window.innerWidth, height = window.innerHeight;
var widthHalf = width / 2, heightHalf = height / 2;

var pos = object.position.clone();
pos.project(camera);
pos.x = ( pos.x * widthHalf ) + widthHalf;
pos.y = - ( pos.y * heightHalf ) + heightHalf;
请注意object.position,如果对象是组的一部分,则可能不是您需要的,因为object.position是组内的本地位置。使用object.getWorldPosition()(or pos.setFromMatrixPosition(),如在其他答案中一样) 将考虑组内的相对定位。
2021-03-16 07:28:47
如果您想准确地获得位置,而不管包含画布(可能不是整个窗口)的位置和大小,您需要将这些计算基于canvas.getBoundingClientRect()而不是window
2021-03-20 07:28:47
此答案假定画布与窗口大小相同。真的应该使用半画布宽度和半画布高度......
2021-04-10 07:28:47

对于获取deprecatedwarnings记录的每个人,接受的答案是旧的 Three.js 版本。现在它更容易:

let pos = new THREE.Vector3();
pos = pos.setFromMatrixPosition(object.matrixWorld);
pos.project(camera);

let widthHalf = canvasWidth / 2;
let heightHalf = canvasHeight / 2;

pos.x = (pos.x * widthHalf) + widthHalf;
pos.y = - (pos.y * heightHalf) + heightHalf;
pos.z = 0;

console.log(pos);
“对象”未定义
2021-03-21 07:28:47
这很好,但是当对象在相机后面时,pos.project()返回一个值,就像对象围绕相机旋转 180 度一样。
2021-03-21 07:28:47
@Jespertheend 你知道关于这个问题的任何解决方案吗?
2021-04-02 07:28:47
@JoãoVilaçaobject应该是THREE.Object3D您尝试转换为屏幕坐标实例(它采用该对象的位置)
2021-04-09 07:28:47
@Jespertheend 感谢您的回答。我通过创建从相机到对象的方向向量并将其与来自相机的 lookAt-Vector 进行比较来解决它。你可以在这里看到它(浏览器-mmo):g13.ennix.io
2021-04-12 07:28:47