基本上我想创建的是:
我有一个包含对象的 3D map ,我想选择屏幕上 2D 框 x1,y1 到 x2,y2 中的所有对象。
关于如何完成的任何想法,因为我对如何开始一无所知。
提前致谢!
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;
}
}
}
最佳答案
在屏幕空间中相交一个盒子相当于在 3D 空间中相交一个金字塔(透视图)或一个立方体(正交 View )。我认为您应该根据您的 2D 框定义一个 THREE.Frustum
。
对于透视相机:
- 将屏幕空间框 Angular 坐标转换为 3D 向量(从相机位置到给定点的向量)
var topLeftCorner3D = new THREE.Vector3( topLeftCorner2D.x, topLeftCorner2D.y, 1 ).unproject( camera );
- 根据这些点构建 4 个平面(一个平面代表盒子的一侧)。平面的第三个点是相机位置。
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);
- 将平截头体与对象相交
frustum.intersectsBox(object.geometry.boundingBox)
或
frustum.intersectsSphere(object.geometry.boundingSphere)
使用 Frustum
对象本身的替代方法:您可以跳过近平面和远平面,您只需检查该对象是否在与您的 4 个平面相邻的空间中。您可以编写一个函数,例如只有 4 个平面的 Frustum.intersectSphere()
方法:
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;
}
关于javascript - Three.js: "select tool"如何检测2D正方形与3D物体的交集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27295415/