ThreeJS raycaster关闭与相机和对象的坐标大于1000000
我已经设置了一个raycaster为了从我的画布执行对象选择。ThreeJS raycaster关闭与相机和对象的坐标大于1000000
它适用于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的一部分,其中 '画布' DIV所在,我也尝试过的,而不是renderer.domElement.offsetLeft等canvas.offsetLef ..
编辑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>
怀疑浮点舍入误差我walke d通过Matlab中的unprojection来了解不同的实现如何处理它。我开始与摄像机矩阵在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
相机投影矩阵通过threejs
逆计算由JavaScript逆相机投影矩阵
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
乘以矩阵一起(逆相机投影矩阵*相机世界矩阵)
在threejs
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中相同的计算
c amProjectionInv * 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],并通过乘以从MATLAB
除以瓦特从threejs
3599999.783405974, 1799999.891702987, 900796.0640709081
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
}
我想肯定的是,一个DOMElement和帆布起源于HTML/CSS坐标是相同的,没有利润,浏览器缩放或偏移正在从您的意图中移动光线。那么你的渲染器setSize也是正确的。由于浮动不精确,我从未见过射线缺失。 – Radio
我会说你的设置有问题。也许你的完整代码的小提琴会帮助别人指出这个问题。 – Wilt
我有同样的问题。但是,如果我旋转并用orbitControls平移我的场景,raycaster会找到相交对象。 你找到了解决办法? –