【问题标题】:ThreeJS raycaster off with camera and object having a coordinate greater than 1000000ThreeJS raycaster 关闭相机和坐标大于 1000000 的对象
【发布时间】:2016-06-22 18:27:28
【问题描述】:

我已经设置了一个光线投射器,以便从我的画布中执行对象选择。

它适用于camera.position.x和object.position.x的小值,但我的问题是当camera.postion.x是一个很大的数字时它不能很好地工作,在我的例子中是10 000 000 !

它偏离了很多,实际上,当鼠标指针在我的对象右侧整个对象长度时,我会做出反应!我的猜测是,用如此庞大的数字进行计算会产生这种失真,但不能确定。

                var raycaster = new THREE.Raycaster();
                var vector = new THREE.Vector2();

                camera.position.x = 11000000;
                object.position.x = 11000000;

                function onMouseMove( event ) {

                    vector.x = ( (event.clientX - renderer.domElement.offsetLeft) / renderer.domElement.clientWidth ) * 2 - 1;
                    vector.y = - ( (event.clientY - renderer.domElement.offsetTop) / renderer.domElement.clientHeight ) * 2 + 1;

                    raycaster.setFromCamera(vector, camera);

                    var intersects = raycaster.intersectObjects(scene.children, true);

                    if(intersects.length>0){
                        alert("INTERSECTION " + intersects[0].object.userData.name);
                        }

                }canvas.addEventListener('mousemove', onMouseMove, false);

我省略了在场景中添加对象和其他一些内容,以便帖子不会太长。例如,当 camera.position.x 和 object.position.x 设置为小于 1 000 000 的某个值时,此方法有效,尽管即使在那时也存在一些失真。

编辑 1

                var scene = new THREE.Scene();

                var canvas = document.getElementById('canvas');

                var height = canvas.clientHeight;
                var width = canvas.clientWidth;

                var camera = new THREE.PerspectiveCamera(70, width/height, 1, 1000);

                var renderer = new THREE.WebGLRenderer();
                renderer.setSize(width, height);
                canvas.appendChild(renderer.domElement);

另外,这是我的 html 的一部分,其中 'canvas' div 所在的位置,我还尝试了 canvas.offsetLef 而不是 renderer.domElement.offsetLeft 等。

编辑 2

<div id="content" ng-controller="ShippingCtrl">

        <div id="left_panel">

        </div>

        <div id="canvas" style="width:900px; height:600px; border:1px solid white">

        </div>

        <div id="right_pannel">

        </div></div>

【问题讨论】:

  • 我想确保 HTML/CSS 中的 domElement 和画布原点坐标是相同的,并且没有边距、浏览器缩放或偏移量使光线偏离您的意图。然后你的渲染器 setSize 也是正确的。我从未见过因为浮动不精确而导致光线未命中的情况。
  • 我会说你的设置有问题。也许修改您的完整代码会帮助其他人指出问题。
  • 我也有同样的问题。但是如果我使用 orbitControls 旋转和平移我的场景,raycaster 会发现相交对象。你找到解决办法了吗?
  • 这是一个codepen,它破解了threejs 交互式立方体demo 来演示这个问题。

标签: javascript three.js camera raycasting


【解决方案1】:

怀疑浮点舍入错误 我浏览了 Matlab 中的非投影,看看不同的实现如何处理它。我从 codepen 示例中的相机矩阵开始

相机投影

 4.951969385147095e-01                         0                         0                         0
                     0     1.428148031234741e+00                         0                         0
                     0                         0    -1.001000523567200e+00    -1.000000000000000e+00
                     0                         0    -2.001000404357910e+00                         0

相机世界

       1           0           0           0
       0           1           0           0
       0           0           1           0
 4000000     2000000     1000800           1

javascript通过threejs计算的相机投影矩阵的逆

逆相机投影矩阵

    2.0193986892700195                          0                           0                       0  
                     0          0.700207531452179                           0                       0  
                     0                          0                           0      -0.499750018119812  
                     0                          0                          -1      0.5002500414848328

Matlab 计算的相机投影矩阵的倒数

 2.019398591193624e+00                         0                         0                         0
                     0     7.002075262012054e-01                         0                         0
                     0                         0                         0    -4.997500239490878e-01
                     0                         0    -1.000000000000000e+00     5.002500356257574e-01

将矩阵相乘(逆相机投影矩阵 * 相机世界矩阵)

在三个js中

    2.0193986892700195                          0                           0                       0  
                     0          0.700207531452179                           0                       0
          -1999000.125               -999500.0625                -500149.8125      -0.499750018119812
           2001000.125               1000500.0625                   500649.25      0.5002500414848328

在Matlab中同样的计算

camProjectionInv*camWorld

 2.019398591193624e+00                         0                         0                         0
                     0     7.002075262012054e-01                         0                         0
-1.999000095796351e+06    -9.995000478981755e+05    -5.001498239682470e+05    -4.997500239490878e-01
 2.001000142503030e+06     1.000500071251515e+06     5.006492356542581e+05     5.002500356257574e-01  

为了简单起见,使用屏幕中心的一个点 [0,0,0.5,1.0] 并乘以除以 w

来自三个js

     3599999.783405974,        1799999.891702987,        900796.0640709081

来自 Matlab

 4.000000000000000e+06     2.000000000000000e+06     1.000796005991391e+06     1.000000000000000e+00

存在舍入误差累积。我不太明白 C++ (Matlab) 和 JavaScript (threejs) 在处理 IEEE 标准 754 64 位浮点数方面有何不同。

对于我的使用而言,保留数据的世界坐标系很重要,因此为了克服拾取/浮点问题,我只需使用它的位置在顶部组节点放置一个平移,将我的场景转换回原点属性并将相机设置为查看该位置。我将我的相机和视图信息与我的场景分开,以便我可以对同一数据实现多个视图。因此,在我的场景对象上,我实现了

center(): THREE.Vector3 {
    let datacenter = this.dataCenter();
    let center = datacenter.add(this.sceneLocation);
    return center;
}

worldBBox(): THREE.Box3 {
    return new THREE.Box3().setFromObject(this.pathsGroup);
}

protected updateScenePosition(): void {
    this.sceneLocation = this.dataCenter().negate();
    this.scene.position.set(this.sceneLocation.x, this.sceneLocation.y, this.sceneLocation.z);
    this.scene.matrixWorldNeedsUpdate=true;
    this.scene.updateMatrixWorld(true);
}

protected dataCenter(): THREE.Vector3 {
    let dataBBox = this.dataBoundingBox();
    let center = dataBBox.max.clone();
    center.sub(dataBBox.min);
    center.divideScalar(2.0);
    center.add(dataBBox.min);
    return center;
}

protected dataBoundingBox(): THREE.Box3 {
    let bbox = new THREE.Box3().setFromObject(this.pathsGroup);
    this.pathsGroup.worldToLocal(bbox.min);
    this.pathsGroup.worldToLocal(bbox.max);

    return bbox;
}

当一个对象被添加到场景中时,我调用 updateScenePosition 虽然它可能不是绝对必要的,因为新对象可能在大致相同的语言环境中,并且可见错误可能已经用初始对象进行了补偿。

然后是相机更新

centerView() : 无效 {

    this.look = this.bigscene.center().clone();

    this.camera.position.set(this.look.x, this.look.y, this.look.z+3600); 

    this.camera.lookAt(this.look);
    this.controls.target.set(this.look.x, this.look.y, this.look.z);

    this.light.position.copy(this.camera.position); //headlight
}

【讨论】:

    猜你喜欢
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-30
    • 2020-09-14
    • 1970-01-01
    • 2018-07-01
    相关资源
    最近更新 更多