在 three.js 中将 Point3D 转换为 Screen2D 得到错误结果

Posted

技术标签:

【中文标题】在 three.js 中将 Point3D 转换为 Screen2D 得到错误结果【英文标题】:convert Point3D To Screen2D get wrong result in three.js 【发布时间】:2015-07-01 04:53:36 【问题描述】:

我在three.js 69中使用这样的函数

  function Point3DToScreen2D(point3D,camera)
    var p = point3D.clone();
    var vector = p.project(camera);

    vector.x = (vector.x + 1) / 2 * window.innerWidth;
    vector.y = -(vector.y - 1) / 2 * window.innerHeight;

    return vector;

  

当我保持场景静止时它工作正常。 但是当我旋转场景时,它犯了一个错误并在屏幕中返回错误的位置。当我旋转大约 180 度时会发生这种情况。它在屏幕上应该没有位置,但它显示了。 p>

我在update 中设置了一个位置var tmpV=Point3DToScreen2D(new THREE.Vector3(-67,1033,-2500),camera); 并用css3d 显示它。当我旋转180 度但小于360 度时,该点再次显示在屏幕上。显然这是一个错误的位置,可以从场景和我没有旋转 360 度。

我对@9​​87654327@知之甚少,所以我不知道project是如何工作的。

这里是three.js中project的来源:

project: function () 

        var matrix;

        return function ( camera ) 

            if ( matrix === undefined ) matrix = new THREE.Matrix4();

            matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
            return this.applyProjection( matrix );

        ;

    ()

matrix.getInverse( camera.matrixWorld ) 是多余的吗?我试图删除它,但它没有用。 谁能帮帮我?谢谢。

【问题讨论】:

复制:***.com/questions/27409074/… 你用来“旋转场景”的代码是什么? @WestLangley 我的意思是这里有一个错误。我使用像threejs.org/examples/webgl_panorama_equirectangular.html这样的普通旋转控件@ @WestLangley 我认为那是因为project 返回 2 个方向的项目。如果我可以进行光线投射,我可能会得到正确的答案,但我不知道如何与屏幕相交。跨度> project() 将点从世界空间投影到标准化设备坐标 (NDC) 空间。你将不得不study some math。如果一个点在相机后面,它也可以投影到 NDC 空间中。也许这就是你所看到的。 【参考方案1】:

您正在使用这样的模式将 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;

但是,使用这种方法,摄像机后面的点也会投影到屏幕空间。

您说过要过滤掉相机后面的点。为此,您可以先使用此模式:

var matrix = new THREE.Matrix4(); // create once and reuse

...

// get the matrix that maps from world space to camera space
matrix.getInverse( camera.matrixWorld );

// transform your point from world space to camera space
p.applyMatrix( matrix );

由于相机位于相机空间中的原点,并且由于相机始终向下看相机空间中的负 z 轴,因此相机后面的点的 z 坐标将大于零。

// check if point is behind the camera
if ( p.z > 0 ) ...

three.js r.71

【讨论】:

好吧,也许我应该说得更清楚一点。我想做的是用 css3d 显示点,点会像在场景中一样移动。所以我应该弄清楚点什么时候在不改变点位置的情况下不在相机视图中。我将创建一个小提琴,您可以对其进行编辑。感谢您的帮助。 我试过if( camera.target.z-(-2500)<0),-2500 是点的z,但它显示了一个错误。该点在 3d 点离开相机视图之前消失。 我更正了我的答案...抱歉,我只能回答有关three.js的问题。我无法为您调试您的代码。希望你能理解。 这工作正常:jsfiddle.net/aboutqx/0sgh361q/18,使用Frustum 来确定该点是否在相机的视野内【参考方案2】:

与上面的示例类似,但您可以检查 vector.z 以确定它是否在前面。

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

//behind the camera if z isn't in 0..1 [frustrum range]
if(vector.z > 1)
   vector = null;

【讨论】:

这不是真的。映射不是连续的。远平面之外的点也映射到大于 1 的 z 值。【参考方案3】:

要深入研究这个答案:

// behind the camera if z isn't in 0..1 [frustrum range]
if(vector.z > 1)
   vector = null;

这不是真的。映射不是连续的。远点以外的点 平面也映射到大于 1 的 z 值

投影矢量的 z 值究竟代表什么? X 和 Y 在归一化剪辑空间 [-1,1] 中,那么 z 呢?

这是真的吗?

projectVector.project(camera);

var inFrontOfCamera = projectVector.z < 1;

【讨论】:

【参考方案4】:

由于相机位于相机空间中的原点,并且由于相机始终向下看相机空间中的负 z 轴,因此相机后面的点的 z 坐标将大于 1。

//check if point is behind the camera
if ( p.z > 1 ) ...

注意:如果满足此条件,则投影坐标需要中心对称

x: 0.233, y: -0.566, z: 1.388
// after transform
x: -0.233, y: 0.566, z: 1.388

【讨论】:

以上是关于在 three.js 中将 Point3D 转换为 Screen2D 得到错误结果的主要内容,如果未能解决你的问题,请参考以下文章

在 Three.js 中将经度和纬度转换为 xyz(为了旋转相机)的问题

在three.js中将带孔的SVG路径转换为挤压形状

将 vector<Point3d> 转换为大小为 (n x 3) 的 Mat,反之亦然

如何在 THREE.JS 中将对象放在相机前面?

将 three.js 模型转换为 svg

在three.js中将网格添加到场景之前如何设置网格的位置