使用 Projection 在 Three.js 中将世界坐标转换为屏幕坐标
Posted
技术标签:
【中文标题】使用 Projection 在 Three.js 中将世界坐标转换为屏幕坐标【英文标题】:Converting World coordinates to Screen coordinates in Three.js using Projection 【发布时间】:2012-07-20 03:41:36 【问题描述】:在 Three.js 中有几个关于 unprojecting 的优秀堆栈问题 (1, 2),即如何将浏览器中的 (x,y) 鼠标坐标转换为 (x,y,z) 坐标在 Three.js 画布空间中。他们大多遵循这种模式:
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 中对象的位置,如何确定它在屏幕上的位置?
似乎没有针对此问题的任何已发布解决方案。 Another question about this just showed up on Stack,但作者声称已经解决了一个对我不起作用的功能的问题。他们的解决方案不使用投影射线,我很确定由于 2D 到 3D 使用 unprojectVector(),因此 3D 到 2D 解决方案将需要 projectVector()。
还有this issue在Github上打开。
感谢任何帮助。
【问题讨论】:
非常感谢“屏幕到世界”的翻译模式。痛了好几个小时.. 【参考方案1】:试试这个:
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;
【讨论】:
另一个堆栈问题的操作发布了这个链接,它也有解决方案。再次感谢! github.com/mrdoob/three.js/issues/78 getPosition() 已被弃用。改用这个: var vector = projection.projectVector(new THREE.Vector3().getPositionFromMatrix(object.matrixWorld), camera); 更新了答案。谢谢@imbrizi! 我认为您的代码在 getPositionFromMatrix 之前缺少向量。所以vector.getPositionFromMatrix 再次修复。对此感到抱歉。【参考方案2】:对于现代 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()
(或pos.setFromMatrixPosition()
,如其他答案)将考虑组内的相对定位。
此答案假定画布与窗口大小相同。真的应该使用一半画布宽度和一半画布高度......
如果您想准确地获取位置,而不管包含画布的位置和大小(可能不是整个窗口),您需要将这些计算基于canvas.getBoundingClientRect()
window
【参考方案3】:
对于获取deprecated
或warnings
日志的每个人,可接受的答案是针对较旧的 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);
【讨论】:
“对象”未定义 这很好,但是当对象在相机后面时,pos.project()
返回一个值,好像对象围绕相机旋转了 180 度。
@Jespertheend 你知道这个问题的任何解决方案吗?
@Jespertheend 感谢您的回答。我通过创建从相机到对象的 directionVector 并将其与相机中的 lookAt-Vector 进行比较来解决它。你可以在这里看到它的实际效果(browser-mmo):g13.ennix.io以上是关于使用 Projection 在 Three.js 中将世界坐标转换为屏幕坐标的主要内容,如果未能解决你的问题,请参考以下文章
使用Three.js 心得系列一 如何创建三维网格三使用Three.js 心得系列三 Three.js 如何加载GlTF文件