【发布时间】:2019-06-17 06:54:06
【问题描述】:
我有一个使用BufferGeometry 创建的Mesh。
我还有鼠标与Mesh 相交的坐标,使用Raycaster。
我正在尝试从交点检测半径范围内(并接触)的人脸。
一旦我检测到“切线”面,我就想给这些面着色。因为我正在使用BufferGeometry,所以我正在处理我的几何图形上的缓冲区属性。
这是我的代码:
let vertexA;
let vertexB;
let vertexC;
let intersection;
const radius = 3;
const color = new THREE.Color('red');
const positionsAttr = mesh.geometry.attributes.position;
const colorAttr = mesh.geometry.attributes.color;
// on every mouseMove event, do below:
vertexA = new THREE.Vector3();
vertexB = new THREE.Vector3();
vertexC = new THREE.Vector3();
intersection = raycaster.intersectObject(mesh).point;
// function to detect tangent edge
function isEdgeTouched(v1, v2, point, radius) {
const line = new THREE.Line3();
const closestPoint = new THREE.Vector3();
line.set(v1, v2);
line.closestPointToPoint(point, true, closestPoint);
return point.distanceTo(closestPoint) < radius;
}
// function to color a face
function colorFace(faceIndex) {
colorAttr.setXYZ(faceIndex * 3 + 0, color.r, color.g, color.b);
colorAttr.setXYZ(faceIndex * 3 + 0, color.r, color.g, color.b);
colorAttr.setXYZ(faceIndex * 3 + 0, color.r, color.g, color.b);
colorAttr.needsUpdate = true;
}
// iterate over each face, color it if tangent
for (let i=0; i < (positionsAttr.count) /3); i++) {
vertexA.fromBufferAttribute(positionsAttr, i * 3 + 0);
vertexB.fromBufferAttribute(positionsAttr, i * 3 + 1);
vertexC.fromBufferAttribute(positionsAttr, i * 3 + 2);
if (isEdgeTouched(vertexA, vertexB, point, radius)
|| isEdgeTouched(vertexA, vertexB, point, radius)
|| isEdgeTouched(vertexA, vertexB, point, radius)) {
colorFace(i);
}
虽然此代码有效,但它的性能似乎很差,尤其是当我使用具有许多面的几何图形时。当我在 Chrome DevTools 上检查性能监视器时,我注意到 isEdgeTouched 和 colorFace 函数在每次迭代中都占用了太多时间。
有没有办法改进这个算法,或者有没有更好的算法来检测相邻的人脸?
编辑
我从 THREE.js slack 频道获得了一些帮助,并修改了算法以使用 Three 的 Sphere。我现在不再做“边缘”检测,而是检查人脸是否在Sphere
更新代码如下:
const sphere = new THREE.Sphere(intersection, radius);
// now checking if each vertex of a face is within sphere
// if all are, then color the face at index i
for (let i=0; i < (positionsAttr.count) /3); i++) {
vertexA.fromBufferAttribute(positionsAttr, i * 3 + 0);
vertexB.fromBufferAttribute(positionsAttr, i * 3 + 1);
vertexC.fromBufferAttribute(positionsAttr, i * 3 + 2);
if (sphere.containsPoint(vertexA)
&& sphere.containsPoint(vertexA)
&& sphere.containsPoint(vertexA)) {
colorFace(i);
}
当我在我的应用程序中进行测试时,我注意到性能明显比以前的版本有所提高。但是,我仍然想知道是否可以进一步改进。
【问题讨论】:
-
不确定它是否更有效,但您是否看过这个解决方案? discourse.threejs.org/t/select-faces-within-radius
-
@Marquizzo 我实际上和那个人谈过(我是最初在三个松弛频道上发布问题的人)。它适用于 2D 平面,但我在尝试以 3D 实现它时遇到了麻烦。此外,他建议的边缘检测算法在具有许多面的更复杂的几何图形上执行时性能不是很好。所以我想看看是否有更有效的方法来做到这一点。
标签: javascript algorithm three.js 3d face