ThreeJS:在PlaneBufferGeometry中查找相邻面

问题描述 投票:0回答:1

我正在寻找一种更好/更快的方法来找到我的PlaneBufferGeometry中的相邻面孔(具有相同的边缘)。目前,我的THREE.Raycaster与我的对象很好相交(使用intersectObject)。但是我需要找到所有周围的面孔。

目前,我使用以下肮脏的方法来查找“隔壁”的面孔。它在我的情况下效果很好,但感觉不正确:

let rc = new THREE.Raycaster();
let intersects = [];
for (let i = -1; i <= 1; i++) {
    for (let j = -1; j <= 1; j++) {
        let v = new THREE.Vector3(x + i, y, z + j);
        rc.set(v, new THREE.Vector3(0, -1, 0));
        rc.near = 0;
        rc.far = 2;
        let subIntersects = rc.intersectObject(mesh);
        for (let n = 0; n < subIntersects.length; n++) {
            intersects.push(subIntersects[n]);
        }
    }
}

例如,是否有一种方法可以在mesh.geometry.attributes.position.array中快速找到这些面孔?欢迎任何建议。预先感谢!

javascript three.js
1个回答
0
投票

您提到了位置数组中的5万个商品。在我看来,这似乎并不慢。这个示例只有10x10,所以数组中有100个项目,因此很容易看到它正在工作,但是我将其设置为200x200,这是40k个项目,而且看起来足够快了吗?

'use strict';

function main() {
  const canvas = document.querySelector('#c');
  const renderer = new THREE.WebGLRenderer({canvas});

  const fov = 60;
  const aspect = 2;  // the canvas default
  const near = 0.1;
  const far = 200;
  const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  camera.position.z = 1;

  const scene = new THREE.Scene();
  scene.background = new THREE.Color('#444');

  scene.add(camera);

  const planeGeometry = new THREE.PlaneBufferGeometry(1, 1, 20, 20);
  const material = new THREE.MeshBasicMaterial({color: 'blue'});
  const plane = new THREE.Mesh(planeGeometry, material);
  scene.add(plane);
  
  const edgeGeometry = new THREE.BufferGeometry();
  const positionNumComponents = 3;
  edgeGeometry.setAttribute('position', planeGeometry.getAttribute('position'));
  edgeGeometry.setIndex([]);
  const edgeMaterial = new THREE.MeshBasicMaterial({
     color: 'yellow', 
     wireframe: true,
     depthTest: false,
  });
  const edges = new THREE.Mesh(edgeGeometry, edgeMaterial);
  scene.add(edges);

  function resizeRendererToDisplaySize(renderer) {
    const canvas = renderer.domElement;
    const width = canvas.clientWidth;
    const height = canvas.clientHeight;
    const needResize = canvas.width !== width || canvas.height !== height;
    if (needResize) {
      renderer.setSize(width, height, false);
    }
    return needResize;
  }

  class PickHelper {
    constructor() {
      this.raycaster = new THREE.Raycaster();
    }
    pick(normalizedPosition, scene, camera, time) {
      // cast a ray through the frustum
      this.raycaster.setFromCamera(normalizedPosition, camera);
      // get the list of objects the ray intersected
      const intersectedObjects = this.raycaster.intersectObjects(scene.children, [plane]);
      if (intersectedObjects.length) {
        // pick the first object. It's the closest one
        const intersection = intersectedObjects[0];
        const faceIndex = intersection.faceIndex;
        const indexAttribute = planeGeometry.getIndex();
        const indices = indexAttribute.array;
        const vertIds = indices.slice(faceIndex * 3, faceIndex * 3 + 3);
        const neighbors = []; // note: self will be added to list
        for (let i = 0; i < indices.length; i += 3) {
          for (let j = 0; j < 3; ++j) {
            const p0Ndx = indices[i + j];
            const p1Ndx = indices[i + (j + 1) % 3];
            if ((p0Ndx === vertIds[0] && p1Ndx === vertIds[1]) ||
                (p0Ndx === vertIds[1] && p1Ndx === vertIds[0]) ||
                (p0Ndx === vertIds[1] && p1Ndx === vertIds[2]) ||
                (p0Ndx === vertIds[2] && p1Ndx === vertIds[1]) ||
                (p0Ndx === vertIds[2] && p1Ndx === vertIds[0]) ||
                (p0Ndx === vertIds[0] && p1Ndx === vertIds[2])) {
                neighbors.push(...indices.slice(i, i + 3));
                break;
            }
          }
        }
        const edgeIndices = edgeGeometry.getIndex();
        edgeIndices.array = new Uint16Array(neighbors);
        edgeIndices.count = neighbors.length;
        edgeIndices.needsUpdate = true;
      }
    }
  }

  const pickPosition = {x: 0, y: 0};
  const pickHelper = new PickHelper();
  clearPickPosition();

  function render(time) {
    time *= 0.001;  // convert to seconds;

    if (resizeRendererToDisplaySize(renderer)) {
      const canvas = renderer.domElement;
      camera.aspect = canvas.clientWidth / canvas.clientHeight;
      camera.updateProjectionMatrix();
    }

    pickHelper.pick(pickPosition, scene, camera, time);

    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }
  requestAnimationFrame(render);

  function getCanvasRelativePosition(event) {
    const rect = canvas.getBoundingClientRect();
    return {
      x: event.clientX - rect.left,
      y: event.clientY - rect.top,
    };
  }

  function setPickPosition(event) {
    const pos = getCanvasRelativePosition(event);
    pickPosition.x = (pos.x / canvas.clientWidth ) *  2 - 1;
    pickPosition.y = (pos.y / canvas.clientHeight) * -2 + 1;  // note we flip Y
  }

  function clearPickPosition() {
    // unlike the mouse which always has a position
    // if the user stops touching the screen we want
    // to stop picking. For now we just pick a value
    // unlikely to pick something
    pickPosition.x = -100000;
    pickPosition.y = -100000;
  }
  window.addEventListener('mousemove', setPickPosition);
  window.addEventListener('mouseout', clearPickPosition);
  window.addEventListener('mouseleave', clearPickPosition);

  window.addEventListener('touchstart', (event) => {
    // prevent the window from scrolling
    event.preventDefault();
    setPickPosition(event.touches[0]);
  }, {passive: false});

  window.addEventListener('touchmove', (event) => {
    setPickPosition(event.touches[0]);
  });

  window.addEventListener('touchend', clearPickPosition);
}

main();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://threejsfundamentals.org/threejs/resources/threejs/r112/build/three.js"></script>
<canvas id="c"></canvas>

就像我在评论中提到的那样。如果您知道它是PlaneBufferGeometry,则可以查看three.js代码,并查看人脸的确切布局,因此,给定faceIndex后,您可以直接计算邻居。上面的代码是通用的,至少对于具有索引的BufferGeometry而言。

如果上面的代码太慢,您也可以预先生成一个faceIndexs到邻居的映射。

© www.soinside.com 2019 - 2024. All rights reserved.