Javascript Three.js:“;选择工具";如何检测二维正方形与三维对象的交点
基本上,我想创建: 我有一个带有对象的3D地图,我想在屏幕上选择2D框x1、y1到x2、y2中的所有对象 我不知道该怎么做,因为我不知道该怎么开始 提前谢谢Javascript Three.js:“;选择工具";如何检测二维正方形与三维对象的交点,javascript,three.js,intersection,raycasting,Javascript,Three.js,Intersection,Raycasting,基本上,我想创建: 我有一个带有对象的3D地图,我想在屏幕上选择2D框x1、y1到x2、y2中的所有对象 我不知道该怎么做,因为我不知道该怎么开始 提前谢谢 prevX和prevY是鼠标按下的坐标: function onDocumentMouseUp(event) { event.preventDefault(); var x = (event.clientX / window.innerWidth) * 2 - 1; var y = -(event.clientY / wind
prevX
和prevY
是鼠标按下的坐标:
function onDocumentMouseUp(event) {
event.preventDefault();
var x = (event.clientX / window.innerWidth) * 2 - 1;
var y = -(event.clientY / window.innerHeight) * 2 + 1;
var width = (x - prevX); //* window.innerWidth;
var height = (y - prevY); //* window.innerHeight;
var dx = prevX; //* window.innerWidth;
var dy = prevY; //* window.innerHeight;
console.log(
dx + ',' +
dy + "," +
(dx + width) + "," +
(dy + height) +
", width=" + width +
", height=" + height
);
var topLeftCorner3D = new THREE.Vector3(dx, dy, 1).unproject(
camera);
var topRightCorner3D = new THREE.Vector3(dx + width, dy, 1)
.unproject(camera);
var bottomLeftCorner3D = new THREE.Vector3(dx, dy + height,
1).unproject(camera);
var bottomRightCorner3D = new THREE.Vector3(dx + width, dy +
height, 1).unproject(camera);
var topPlane = new THREE.Plane();
var rightPlane = new THREE.Plane();
var bottomPlane = new THREE.Plane();
var leftPlane = new THREE.Plane();
topPlane.setFromCoplanarPoints(camera.position,
topLeftCorner3D, topRightCorner3D);
rightPlane.setFromCoplanarPoints(camera.position,
topRightCorner3D, bottomRightCorner3D);
bottomPlane.setFromCoplanarPoints(camera.position,
bottomRightCorner3D, bottomLeftCorner3D);
leftPlane.setFromCoplanarPoints(camera.position,
bottomLeftCorner3D, topLeftCorner3D);
//var frustum = new THREE.Frustum( topPlane, bottomPlane, leftPlane, rightPlane, nearPlane, farPlane);
function isObjectInFrustum(object3D) {
var sphere = object3D.geometry.boundingSphere;
var center = sphere.center;
var negRadius = -sphere.radius;
if (topPlane.distanceToPoint(center) < negRadius) { return false; }
if (bottomPlane.distanceToPoint(center) < negRadius) { return false; }
if (rightPlane.distanceToPoint(center) < negRadius) { return false; }
if (leftPlane.distanceToPoint(center) < negRadius) { return false; }
return true;
}
var matches = [];
for (var i = 0; i < window.objects.length; i++) {
if (isObjectInFrustum(window.objects[i])) {
window.objects[i].material = window.selectedMaterial;
}
}
}
函数onDocumentMouseUp(事件){
event.preventDefault();
var x=(event.clientX/window.innerWidth)*2-1;
变量y=-(event.clientY/window.innerHeight)*2+1;
变量宽度=(x-prevX);//*window.innerWidth;
变量高度=(y-上一个);//*window.innerHeight;
var dx=prevX;//*window.innerWidth;
var dy=prevY;//*window.innerHeight;
console.log(
dx+','+
dy+“,”+
(dx+宽度)+“,”+
(dy+高度)+
“,width=“+width+
“,height=“+height
);
var topLeftCorner3D=新的三个向量3(dx,dy,1)。取消投影(
摄像机);
var topRightCorner3D=新的三个矢量3(dx+宽度,dy,1)
.未投影(摄像机);
var bottomLeftCorner3D=新的三个矢量3(dx,dy+高度,
1) .未投影(摄像机);
var bottomRightCorner3D=新的三个矢量3(dx+宽度,dy+
高度,1)。未投影(摄像机);
var topPlane=新的三个平面();
var rightPlane=new THREE.Plane();
var bottomPlane=新的三个平面();
var leftPlane=new THREE.Plane();
topPlane.setFromCoplanarPoints(camera.position,
topLeftCorner3D、topRightCorner3D);
右平面。从共面点(camera.position,
topRightCorner3D,bottomRightCorner3D);
底部平面。从共面点(camera.position,
bottomRightCorner3D、bottomLeftCorner3D);
leftPlane.setFromCoplanarPoints(camera.position,
底部LeftCorner3D、顶部LeftCorner3D);
//var frustum=新的三个截头体(顶平面、底平面、左平面、右平面、近平面、远平面);
函数isObjectInFrustum(object3D){
var sphere=object3D.geometry.boundingSphere;
var center=sphere.center;
var negRadius=-sphere.radius;
if(topPlane.distanceToPoint(center)
您可以使用对象的边界框<代码>三。几何体包含一个边界框
属性。默认情况下这是null
,您应该直接调用computeBoundingBox()
来计算它
scene.traverse( function ( node ) {
if ( node.geometry )
node.geometry.computeBoundingBox();
} );
拥有边界框后,边界框二维坐标为(如果“y”是上方向轴):
看
(但是,如果需要非矩形网格的精确结果,则需要进一步计算)与屏幕空间中的长方体相交相当于与三维空间中的棱锥体(透视)或立方体(正交视图)相交。我认为你应该根据你的2D框定义一个
THREE.trustum
对于透视摄影机:
平截头体
对象本身的替代方法:可以跳过近平面和远平面,只需检查对象是否位于与4个平面相邻的空间中。您可以编写一个类似于trustum.intersectSphere()
方法的函数,该函数只有4个平面:
function isObjectInFrustum(object3D) {
var sphere = object3D.geometry.boundingSphere;
var center = sphere.center;
var negRadius = - sphere.radius;
if ( topPlane.distanceToPoint( center )< negRadius ) return false;
if ( bottomPlane.distanceToPoint( center )< negRadius ) return false;
if ( rightPlane.distanceToPoint( center )< negRadius ) return false;
if ( leftPlane.distanceToPoint( center )< negRadius ) return false;
return true;
}
函数isObjectInFrustum(object3D){
var sphere=object3D.geometry.boundingSphere;
var center=sphere.center;
var negRadius=-sphere.radius;
if(topPlane.distanceToPoint(center)
有关比底壳选择更精确的方法,请参阅。它的工作原理是将边界框的8个角投影到屏幕空间,然后与屏幕矩形相交。第三种更快的方法(用ClojureScript编写)将3D边界球体投影到屏幕空间的边界圆上,以及前两种方法的实现。它尝试使用GPU执行屏幕投影和readpixels拾取(我没有研究过这种方法,因为我认为readpixels会使渲染管道过多地暂停,但如果我错了,请告诉我)
我在上做了一个底壳选择的工作示例,但它太不准确了。重要的部分是:
var rx1 = ( x1 / window.innerWidth ) * 2 - 1;
var rx2 = ( x2 / window.innerWidth ) * 2 - 1;
var ry1 = -( y1 / window.innerHeight ) * 2 + 1;
var ry2 = -( y2 / window.innerHeight ) * 2 + 1;
var projectionMatrix = new THREE.Matrix4();
projectionMatrix.makeFrustum( rx1, rx2, ry1, ry2, camera.near, camera.far );
camera.updateMatrixWorld();
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
var viewProjectionMatrix = new THREE.Matrix4();
viewProjectionMatrix.multiplyMatrices( projectionMatrix, camera.matrixWorldInverse );
var frustum = new THREE.Frustum();
frustum.setFromMatrix( viewProjectionMatrix );
谢谢,我明天去看看。然而,我不确定
var rx1 = ( x1 / window.innerWidth ) * 2 - 1;
var rx2 = ( x2 / window.innerWidth ) * 2 - 1;
var ry1 = -( y1 / window.innerHeight ) * 2 + 1;
var ry2 = -( y2 / window.innerHeight ) * 2 + 1;
var projectionMatrix = new THREE.Matrix4();
projectionMatrix.makeFrustum( rx1, rx2, ry1, ry2, camera.near, camera.far );
camera.updateMatrixWorld();
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
var viewProjectionMatrix = new THREE.Matrix4();
viewProjectionMatrix.multiplyMatrices( projectionMatrix, camera.matrixWorldInverse );
var frustum = new THREE.Frustum();
frustum.setFromMatrix( viewProjectionMatrix );