我需要 Three.js 代码将 3D 对象坐标转换为“div”元素中的 2D 坐标,以便我可以将文本标签放置在需要的位置(这些标签不会随着 3D 运动而缩放/移动/旋转)。不幸的是,到目前为止我所看到和尝试过的所有示例似乎都在使用过时的函数/技术。就我而言,我相信我正在使用 Three.js 的 r69。
这是一个“旧”技术的示例,它只会给我带来错误:
这是一些较新代码的片段(?),它没有为我提供足够的上下文来开始工作,但看起来更干净:
我为我的项目编写了以下函数;它接收
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';
您可以使用如下模式将 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
对我来说这个函数有效(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 中使用,并且添加了画布的偏移量,因为有时画布嵌入到另一个 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
};
};