如何在three.js中使用矩形选择(功能区)选择和突出显示多个对象 [英] How to select and highlight multiple objects with rectangular selection (ribbon) in three.js

查看:152
本文介绍了如何在three.js中使用矩形选择(功能区)选择和突出显示多个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这里,我尝试在鼠标拖动中使用边界框绘制一个矩形,并突出显示矩形内的对象.使用 box3(边界框)在鼠标向下和鼠标向上绘制矩形并突出显示矩形(边界框)内的特定对象.我想我可以通过选择边界框内的对象来实现它们,我对此没有明确的想法.这是小提琴

什么是Frustum,以及它是如何工作的:https://www.youtube.com/watch?v=KyTaxN2XUyQ

<小时>

您将在此处找到完整的解决方案,请按照我在代码中的注释进行操作:

//这就是解决方案的核心,//它通过给定的相机和鼠标坐标构建 Frustum 对象功能更新视锥(相机,mousePos0,mousePos1,视锥){让 pos0 = new THREE.Vector3(Math.min(mousePos0.x, mousePos1.x), Math.min(mousePos0.y, mousePos1.y));让 pos1 = new THREE.Vector3(Math.max(mousePos0.x, mousePos1.x), Math.max(mousePos0.y, mousePos1.y));//首先构建近平面和远平面{//相机方向是近视锥平面的法向量//说 - 飞机正在远离"你让 cameraDir = new THREE.Vector3();相机.getWorldDirection(cameraDir);//反转!相机方向成为远视锥平面的法向量//说 - 飞机面向你"让 cameraDirInv = cameraDir.clone().negate();//计算视图中间的点,并位于近平面上让 cameraNear = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.near));//计算位于视图中间且位于远平面上的点让 cameraFar = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.far));//只需按法线+点构建近平面和远平面frustum.planes[0].setFromNormalAndCoplanarPoint(cameraDir, cameraNear);frustum.planes[1].setFromNormalAndCoplanarPoint(cameraDirInv, cameraFar);}//接下来的 4 个平面(左、右、上、下)由 3 个点构成://相机位置 + 远平面上的两点//每次我们通过鼠标坐标从相机构建光线投射时,//并找到与远平面的交点.////要构建一个平面,我们需要与远平面有 2 个交点.//这就是为什么鼠标坐标会被复制并且//在垂直或水平方向调整"//在左侧建立视锥平面如果是真的) {让 ray = new THREE.Ray();ray.origin.setFromMatrixPosition(camera.matrixWorld);//这是示例,我们取鼠标的 X 坐标,并将 Y 设置为 -0.25 和 0.25//这里的值无关紧要,重要的是光线将投射两个不同的点以形成//垂直对齐的平截头体平面.ray.direction.set(pos0.x, -0.25, 1).unproject(camera).sub(ray.origin).normalize();让 far1 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1], far1);ray.origin.setFromMatrixPosition(camera.matrixWorld);//和之前一样,制作第二条光线ray.direction.set(pos0.x, 0.25, 1).unproject(camera).sub(ray.origin).normalize();让 far2 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1],far2);frustum.planes[2].setFromCoplanarPoints(camera.position, far1, far2);}//在右侧建立视锥平面如果是真的) {让 ray = new THREE.Ray();ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(pos1.x, 0.25, 1).unproject(camera).sub(ray.origin).normalize();让 far1 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1], far1);ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(pos1.x, -0.25, 1).unproject(camera).sub(ray.origin).normalize();让 far2 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1],far2);frustum.planes[3].setFromCoplanarPoints(camera.position, far1, far2);}//在顶部建立视锥平面如果是真的) {让 ray = new THREE.Ray();ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(0.25, pos0.y, 1).unproject(camera).sub(ray.origin).normalize();让 far1 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1], far1);ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(-0.25, pos0.y, 1).unproject(camera).sub(ray.origin).normalize();让 far2 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1],far2);frustum.planes[4].setFromCoplanarPoints(camera.position, far1, far2);}//在底部建立视锥平面如果是真的) {让 ray = new THREE.Ray();ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(-0.25, pos1.y, 1).unproject(camera).sub(ray.origin).normalize();让 far1 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1], far1);ray.origin.setFromMatrixPosition(camera.matrixWorld);ray.direction.set(0.25, pos1.y, 1).unproject(camera).sub(ray.origin).normalize();让 far2 = new THREE.Vector3();ray.intersectPlane(frustum.planes[1],far2);frustum.planes[5].setFromCoplanarPoints(camera.position, far1, far2);}}//检查对象是否在给定的视锥体内,//并相应地更新对象材质功能选择对象(对象,视锥体){//这里数组中的每个对象本质上都是一条记录://{//obj: 场景对象,//选择:标志,//bbox: 世界坐标中对象的边界框//}for (let key of Object.keys(objects)) {//Three.js Frustum 不能与网格相交,//它只能与盒子、球体相交(主要是出于性能原因)//TODO://让它精确地处理复杂的网格,//Frustum需要检查Sphere、Box,然后迭代//通过网格顶点数组(好吧,我知道,这会很慢)if (frustum.intersectsBox(objects[key].bbox)) {如果 (!objects[key].selected) {objects[key].obj.material = selectedMaterial;}对象[key].selected = true;} 别的 {if (objects[key].selected) {objects[key].obj.material = defaultMaterial;}对象[key].selected = false;}}}//==three.js 例程从这里开始 ==//没什么特别的,只是创建一个场景const SHOW_FRUSTUM_PLANES = false;var 渲染器;var 控件;var scene = new THREE.Scene();var camera = new THREE.PerspectiveCamera(54, window.innerWidth/window.innerHeight, 1, 100);相机.位置.x = 5;相机.位置.y = 5;相机.位置.z = 5;相机.lookAt(0, 0, 0);//此相机用于渲染选择功能区var ocamera = new THREE.OrthographicCamera(window.innerWidth/-2, window.innerWidth/2, window.innerHeight/2, window.innerHeight/-2, 0.1, 1000);场景.添加(相机);camera.position.x = 0;camera.position.y = 0;camera.position.z = 100;//这个没关系,就远了ocamera.lookAt(0, 0, 0);//重要信息,相机和功能区位于第 1 层,//这里我们按层渲染,来自两个不同的相机camera.layers.set(1);渲染器 = 新的 THREE.WebGLRenderer({抗锯齿:真});renderer.setSize(window.innerWidth, window.innerHeight);renderer.setPixelRatio(window.devicePixelRatio);renderer.setClearColor(new THREE.Color(0xf9f9f9));document.body.appendChild(renderer.domElement);控件 = 新的 THREE.OrbitControls(camera);//没用过,这里就放弃了//添加一些灯var spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI/4);spotLight.position.set(4, 10, 7);场景添加(聚光灯);变量大小 = 6;var 划分 = 6;var gridHelper = new THREE.GridHelper(size, Divisions);场景添加(gridHelper);//此材质用于正常物体状态var defaultMaterial = new THREE.MeshPhongMaterial({颜色:0x90a090});//此材质用于选定对象状态var selectedMaterial = new THREE.MeshPhongMaterial({颜色:0x20ff20});var 立方体 = {};//生成一些随机立方体for (让 i = -2; i <= 2; i++) {for (让 j = -2; j <= 2; j++) {让宽度 = 0.25 + Math.random() * 0.25;让高度 = 0.25 + Math.random() * 0.5;让长度 = 宽度 + Math.random() * 0.25;let cubeGeometry = new THREE.BoxGeometry(length, height, width);let cube = new THREE.Mesh(cubeGeometry, defaultMaterial);cube.applyMatrix(new THREE.Matrix4().makeTranslation(i, height/2, j));cubeGeometry.computeBoundingBox();让 bbox = cubeGeometry.boundingBox.clone();bbox.applyMatrix4(cube.matrix);场景.添加(立方体);立方体[cube.uuid] = {obj: cube,//我们需要映射对象selected: false,//到某个标志bbox: bbox//并记住它是边界框(以避免每次鼠标移动时重新计算)};}}//选择功能区var material = new THREE.LineBasicMaterial({颜色:0x900090});var geometry = new THREE.Geometry();geometry.vertices.push(new THREE.Vector3(-1, -1, 0));geometry.vertices.push(new THREE.Vector3(-1, 1, 0));geometry.vertices.push(new THREE.Vector3(1, 1, 0));geometry.vertices.push(new THREE.Vector3(1, -1, 0));geometry.vertices.push(new THREE.Vector3(-1, -1, 0));var line = new THREE.Line(geometry, material);line.layers.set(1);//重要,这将转到第 1 层,其他所有内容默认保留在第 0 层line.visible = false;场景添加(行);let frustum = new THREE.Frustum();//这个助手将可视化平截头体平面,//我把它留在这里是为了调试如果(SHOW_FRUSTUM_PLANES){let helper0 = new THREE.PlaneHelper(frustum.planes[0], 1, 0xffff00);场景添加(helper0);让 helper1 = new THREE.PlaneHelper(frustum.planes[1], 1, 0xffff00);场景添加(helper1);让 helper2 = new THREE.PlaneHelper(frustum.planes[2], 1, 0xffff00);场景添加(helper2);let helper3 = new THREE.PlaneHelper(frustum.planes[3], 1, 0xffff00);场景添加(helper3);let helper4 = new THREE.PlaneHelper(frustum.planes[4], 1, 0xffff00);场景添加(helper4);let helper5 = new THREE.PlaneHelper(frustum.planes[5], 1, 0xffff00);场景添加(helper5);}让 pos0, pos1;//鼠标坐标//你可以在这里找到这个类的代码:https://github.com/nmalex/three.js-helpersvar mouse = new RayysMouse(渲染器,相机,控件);//订阅我的助手类,以接收鼠标坐标//方便的格式鼠标.订阅(函数 handleMouseDown(pos, sender) {//使选择功能区可见line.visible = true;//更新色带形状顶点以匹配鼠标坐标for (让 i = 0; i < line.geometry.vertices.length; i++) {line.geometry.vertices[i].x = sender.rawCoords.x;line.geometry.vertices[i].y = sender.rawCoords.y;}geometry.verticesNeedUpdate = true;//记住我们从哪里开始pos0 = pos.clone();pos1 = pos.clone();//更新视锥体为当前鼠标坐标更新视锥体(相机,pos0,pos1,视锥体);//尝试选择/取消选择一些对象选择对象(立方体,视锥体);},函数 handleMouseMove(pos, sender) {如果(sender.mouseDown){line.geometry.vertices[1].y = sender.rawCoords.y;line.geometry.vertices[2].x = sender.rawCoords.x;line.geometry.vertices[2].y = sender.rawCoords.y;line.geometry.vertices[3].x = sender.rawCoords.x;geometry.verticesNeedUpdate = true;//pos0 - 鼠标按下事件发生的地方,//pos1 - 鼠标移动的位置pos1.copy(pos);//更新视锥体为当前鼠标坐标更新视锥体(相机,pos0,pos1,视锥体);//尝试选择/取消选择一些对象选择对象(立方体,视锥体);}},函数 handleMouseUp(pos) {//隐藏选择功能区line.visible = false;});var animate = function() {请求动画帧(动画);控制更新();//从透视相机渲染场景//渲染 layer#0,因为相机属于它renderer.render(场景,相机);renderer.autoClear = false;//在图层#1 中渲染选择功能区,因为相机属于它renderer.render(场景,相机);renderer.autoClear = true;};动画();

Here I'm trying draw a rect using bounding box in mouse drag and hightlight the objects inside the rect. To draw a rect using box3 (bounding box) on mouse down and mouse up and highlight the particular object inside the rect(bounding box). I think I can achieve them with picking the object inside the bounding box which I don't have a clear idea towards it. Here's the fiddle https://jsfiddle.net/mc7dxokr/

var camera, scene, renderer, mesh, material, controls;
        init();
        animate();
        addCubes();
        render();


        function addCubes() {
            var xDistance = 50;
            var zDistance = 30;
            var geometry = new THREE.BoxGeometry(10, 10, 10);
            var material = new THREE.MeshBasicMaterial({ color: 0x00ff44 });

            //initial offset so does not start in middle.
            var xOffset = -80;

            for (var i = 0; i < 4; i++) {
                for (var j = 0; j < 3; j++) {
                    var mesh = new THREE.Mesh(geometry, material);
                    mesh.position.x = (xDistance * i) + xOffset;
                    mesh.position.z = (zDistance * j);
                    scene.add(mesh);
                }
            };
        }

        function init() {
            // Renderer.
            renderer = new THREE.WebGLRenderer();
            //renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(window.innerWidth, window.innerHeight);
            // Add renderer to page
            document.body.appendChild(renderer.domElement);

            // Create camera.
            camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
            camera.position.z = 100;

            // Add controls
            controls = new THREE.TrackballControls(camera);
            controls.addEventListener('change', render);
            controls.enabled = false;

            // Create scene.
            scene = new THREE.Scene();

            // Create ambient light and add to scene.
            var light = new THREE.AmbientLight(0x404040); // soft white light
            scene.add(light);

            // Create directional light and add to scene.
            var directionalLight = new THREE.DirectionalLight(0xffffff);
            directionalLight.position.set(1, 1, 1).normalize();
            scene.add(directionalLight);

            // Add listener for window resize.
            window.addEventListener('resize', onWindowResize, false);
        }

        function animate() {
            requestAnimationFrame(animate);
            controls.update();

        }

        function render() {
            renderer.render(scene, camera);
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
            controls.handleResize();
        }

解决方案

Two ways of rendering rectangular ribbons on top of 3D are:

  • <div> element overlaying webgl canvas (presented here http://output.jsbin.com/tamoce/3/)
  • three.js Line rendered from OrthographicCamera (will be presented in my answer below)

DEMO: http://jsfiddle.net/mmalex/40ucrd8g/

What is Frustum, and how it works: https://www.youtube.com/watch?v=KyTaxN2XUyQ


Complete solution you will find here, follow my comments in code:

// this is the core of the solution,
// it builds the Frustum object by given camera and mouse coordinates
function updateFrustrum(camera, mousePos0, mousePos1, frustum) {
    let pos0 = new THREE.Vector3(Math.min(mousePos0.x, mousePos1.x), Math.min(mousePos0.y, mousePos1.y));
    let pos1 = new THREE.Vector3(Math.max(mousePos0.x, mousePos1.x), Math.max(mousePos0.y, mousePos1.y));

    // build near and far planes first
    {
        // camera direction IS normal vector for near frustum plane
        // say - plane is looking "away" from you
        let cameraDir = new THREE.Vector3();
        camera.getWorldDirection(cameraDir);

        // INVERTED! camera direction becomes a normal vector for far frustum plane
        // say - plane is "facing you"
        let cameraDirInv = cameraDir.clone().negate();

        // calc the point that is in the middle of the view, and lies on the near plane
        let cameraNear = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.near));

        // calc the point that is in the middle of the view, and lies on the far plane
        let cameraFar = camera.position.clone().add(cameraDir.clone().multiplyScalar(camera.far));

        // just build near and far planes by normal+point
        frustum.planes[0].setFromNormalAndCoplanarPoint(cameraDir, cameraNear);
        frustum.planes[1].setFromNormalAndCoplanarPoint(cameraDirInv, cameraFar);
    }

    // next 4 planes (left, right, top and bottom) are built by 3 points:
    // camera postion + two points on the far plane
    // each time we build a ray casting from camera through mouse coordinate, 
    // and finding intersection with far plane.
    // 
    // To build a plane we need 2 intersections with far plane.
    // This is why mouse coordinate will be duplicated and 
    // "adjusted" either in vertical or horizontal direction

    // build frustrum plane on the left
    if (true) {
        let ray = new THREE.Ray();
        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        // Here's the example, - we take X coordinate of a mouse, and Y we set to -0.25 and 0.25 
        // values do not matter here, - important that ray will cast two different points to form 
        // the vertically aligned frustum plane.
        ray.direction.set(pos0.x, -0.25, 1).unproject(camera).sub(ray.origin).normalize();
        let far1 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far1);

        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        // Same as before, making 2nd ray
        ray.direction.set(pos0.x, 0.25, 1).unproject(camera).sub(ray.origin).normalize();
        let far2 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far2);

        frustum.planes[2].setFromCoplanarPoints(camera.position, far1, far2);
    }

    // build frustrum plane on the right
    if (true) {
        let ray = new THREE.Ray();
        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(pos1.x, 0.25, 1).unproject(camera).sub(ray.origin).normalize();
        let far1 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far1);

        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(pos1.x, -0.25, 1).unproject(camera).sub(ray.origin).normalize();
        let far2 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far2);

        frustum.planes[3].setFromCoplanarPoints(camera.position, far1, far2);
    }

    // build frustrum plane on the top
    if (true) {
        let ray = new THREE.Ray();
        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(0.25, pos0.y, 1).unproject(camera).sub(ray.origin).normalize();
        let far1 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far1);

        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(-0.25, pos0.y, 1).unproject(camera).sub(ray.origin).normalize();
        let far2 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far2);

        frustum.planes[4].setFromCoplanarPoints(camera.position, far1, far2);
    }

    // build frustrum plane on the bottom
    if (true) {
        let ray = new THREE.Ray();
        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(-0.25, pos1.y, 1).unproject(camera).sub(ray.origin).normalize();
        let far1 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far1);

        ray.origin.setFromMatrixPosition(camera.matrixWorld);
        ray.direction.set(0.25, pos1.y, 1).unproject(camera).sub(ray.origin).normalize();
        let far2 = new THREE.Vector3();
        ray.intersectPlane(frustum.planes[1], far2);

        frustum.planes[5].setFromCoplanarPoints(camera.position, far1, far2);
    }
}

// checks if object is inside of given frustum,
// and updates the object material accordingly
function selectObjects(objects, frustum) {
    // each object in array here is essentially a record:
    // {
    //   obj: scene object,
    //   selected: flag,
    //   bbox: object's bounding box in world coordinates
    // }

    for (let key of Object.keys(objects)) {
        // three.js Frustum can not intersect meshes,
        // it can only intersect boxes, spheres (mainly for performance reasons)
        // TODO: // to make it precisely work with complex meshes, 
        // Frustum needs to check Sphere, Box, and then iterate 
        // throuh mesh vertices array (well, I know, this will be slow)
        if (frustum.intersectsBox(objects[key].bbox)) {
            if (!objects[key].selected) {
                objects[key].obj.material = selectedMaterial;
            }
            objects[key].selected = true;
        } else {
            if (objects[key].selected) {
                objects[key].obj.material = defaultMaterial;
            }
            objects[key].selected = false;
        }
    }
}

// == three.js routine starts here == 
// nothing special, just creating a scene

const SHOW_FRUSTUM_PLANES = false;

var renderer;
var controls;

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 1, 100);
camera.position.x = 5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(0, 0, 0);

// this camera is used to render selection ribbon
var ocamera = new THREE.OrthographicCamera(window.innerWidth / -2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / -2, 0.1, 1000);
scene.add(ocamera);

ocamera.position.x = 0;
ocamera.position.y = 0;
ocamera.position.z = 100; // this does not matter, just far away

ocamera.lookAt(0, 0, 0);
// IMPORTANT, camera and ribbon are in layer#1,
// Here we render by layers, from two different cameras
ocamera.layers.set(1);

renderer = new THREE.WebGLRenderer({
    antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(new THREE.Color(0xf9f9f9));
document.body.appendChild(renderer.domElement);

controls = new THREE.OrbitControls(camera); // not used, just abandoned it here

// add some lights
var spotLight = new THREE.SpotLight(0xffffff, 2.5, 25, Math.PI / 4);
spotLight.position.set(4, 10, 7);
scene.add(spotLight);

var size = 6;
var divisions = 6;
var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);

// this material is used for normal object state
var defaultMaterial = new THREE.MeshPhongMaterial({
    color: 0x90a090
});

// this material is used for selected object state
var selectedMaterial = new THREE.MeshPhongMaterial({
    color: 0x20ff20
});

var cubes = {};
// generate some random cubes
for (let i = -2; i <= 2; i++) {
    for (let j = -2; j <= 2; j++) {
        let width = 0.25 + Math.random() * 0.25;
        let height = 0.25 + Math.random() * 0.5;
        let length = width + Math.random() * 0.25;

        let cubeGeometry = new THREE.BoxGeometry(length, height, width);
        let cube = new THREE.Mesh(cubeGeometry, defaultMaterial);
        cube.applyMatrix(new THREE.Matrix4().makeTranslation(i, height / 2, j));
        cubeGeometry.computeBoundingBox();
        let bbox = cubeGeometry.boundingBox.clone();
        bbox.applyMatrix4(cube.matrix);
        scene.add(cube);

        cubes[cube.uuid] = {
            obj: cube, // we need to map the object
            selected: false, // to some flag
            bbox: bbox // and remember it's bounding box (to avoid recalculations on each mouse move)
        };
    }
}

// selection ribbon
var material = new THREE.LineBasicMaterial({
    color: 0x900090
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(-1, -1, 0));
geometry.vertices.push(new THREE.Vector3(-1, 1, 0));
geometry.vertices.push(new THREE.Vector3(1, 1, 0));
geometry.vertices.push(new THREE.Vector3(1, -1, 0));
geometry.vertices.push(new THREE.Vector3(-1, -1, 0));
var line = new THREE.Line(geometry, material);
line.layers.set(1); // IMPORTANT, this goes to layer#1, everything else remains in layer#0 by default
line.visible = false;
scene.add(line);

let frustum = new THREE.Frustum();

// this helpers will visualize frustum planes,
// I keep it here for debug reasons
if (SHOW_FRUSTUM_PLANES) {
    let helper0 = new THREE.PlaneHelper(frustum.planes[0], 1, 0xffff00);
    scene.add(helper0);
    let helper1 = new THREE.PlaneHelper(frustum.planes[1], 1, 0xffff00);
    scene.add(helper1);
    let helper2 = new THREE.PlaneHelper(frustum.planes[2], 1, 0xffff00);
    scene.add(helper2);
    let helper3 = new THREE.PlaneHelper(frustum.planes[3], 1, 0xffff00);
    scene.add(helper3);
    let helper4 = new THREE.PlaneHelper(frustum.planes[4], 1, 0xffff00);
    scene.add(helper4);
    let helper5 = new THREE.PlaneHelper(frustum.planes[5], 1, 0xffff00);
    scene.add(helper5);
}

let pos0, pos1; // mouse coordinates

// You find the code for this class here: https://github.com/nmalex/three.js-helpers
var mouse = new RayysMouse(renderer, camera, controls);

// subscribe my helper class, to receive mouse coordinates
// in convenient format
mouse.subscribe(
    function handleMouseDown(pos, sender) {
        // make selection ribbon visible
        line.visible = true;

        // update ribbon shape verts to match the mouse coordinates
        for (let i = 0; i < line.geometry.vertices.length; i++) {
            line.geometry.vertices[i].x = sender.rawCoords.x;
            line.geometry.vertices[i].y = sender.rawCoords.y;
        }
        geometry.verticesNeedUpdate = true;

        // remember where we started
        pos0 = pos.clone();
        pos1 = pos.clone();

        // update frustum to the current mouse coordinates
        updateFrustrum(camera, pos0, pos1, frustum);

        // try to select/deselect some objects
        selectObjects(cubes, frustum);
    },
    function handleMouseMove(pos, sender) {
        if (sender.mouseDown) {
            line.geometry.vertices[1].y = sender.rawCoords.y;

            line.geometry.vertices[2].x = sender.rawCoords.x;
            line.geometry.vertices[2].y = sender.rawCoords.y;

            line.geometry.vertices[3].x = sender.rawCoords.x;

            geometry.verticesNeedUpdate = true;

            // pos0 - where mouse down event occurred,
            // pos1 - where the mouse was moved
            pos1.copy(pos);

            // update frustum to the current mouse coordinates
            updateFrustrum(camera, pos0, pos1, frustum);

            // try to select/deselect some objects
            selectObjects(cubes, frustum);
        }
    },
    function handleMouseUp(pos) {
        // hide selection ribbon
        line.visible = false;
    }
);

var animate = function() {
    requestAnimationFrame(animate);
    controls.update();

    // render the scene from perspective camera
    // render layer#0 as camera belongs to it
    renderer.render(scene, camera);
    renderer.autoClear = false;

    // render selection ribbon in layer#1 as ocamera belongs to it
    renderer.render(scene, ocamera);
    renderer.autoClear = true;
};

animate();

这篇关于如何在three.js中使用矩形选择(功能区)选择和突出显示多个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆