javascriptthree.jsraycasting

THREE .JS raycasting performance


I am trying to find the closest distance from a point to large, complex Mesh along a plane in a direction range:

 for (var zDown in verticalDistances) {
    var myIntersect = {};  
   for (var theta = Math.PI / 2 - 0.5; theta < Math.PI / 2 + 0.5; theta += 0.3) {
                var rayDirection = new THREE.Vector3(
                    Math.cos(theta),
                    Math.sin(theta),
                    0
                ).transformDirection(object.matrixWorld);
                 //  console.log(rayDirection);

                _raycaster.set(verticalDistances[zDown].minFacePoint, rayDirection, 0, 50);
                //  console.time('raycast: ');
                var intersect = _raycaster.intersectObject(planeBufferMesh);
                //   console.timeEnd('raycast: '); // this is huge!!! ~ 2,300 ms

                //   console.log(_raycaster);
                //    console.log(intersect);
                if (intersect.length == 0) continue;
                if ((!('distance' in myIntersect)) || myIntersect.distance > intersect[0].distance) {
                    myIntersect.distance = intersect[0].distance;
                    myIntersect.point = intersect[0].point.clone();
                }
            }
// do stuff
}

I get great results with mouse hover on the same surface but when performing this loop the raycasting is taking over 2 seconds per cast. The only thing i can think of is that the BackSide of the DoubleSide Material is a ton slower?

Also i notice as I space out my verticalDistances[zDown].minFacePoint to be farther apart raycast starts to speed up up (500ms /cast). So as the distance between verticalDistances[i].minFacePoint and verticalDistances[i+1].minFacePoint increases, the raycaster performs faster.

I would go the route of using octree but the mouse hover event works extremely well on the exact same planeBuffer. Is this a side of Material issue,. that could be solved by loading 2 FrontSide meshes pointing in opposite directions?

Thank You!!!!

EDIT: it is not a front back issue. I ran my raycast down the front and back side of the plane buffer geometry with the same spot result. Live example coming.

EDIT 2: working example here. Performance is little better than Original case but still too slow. I need to move the cylinder in real time. I can optimize a bit by finding certain things, but mouse hover is instant. When you look at the console time the first two(500ms) are the results i am getting for all results.

EDIT 3: added a mouse hover event, that performs the same as the other raycasters. I am not getting results in my working code that i get in this sample though. The results I get for all raycast are the same as i get for the first 1 or 2 in the sample around 500ms. If i could get it down to 200ms i can target the items i am looking for and do way less raycasting. I am completely open to suggestions on better methods. Is octree the way to go?

raycast: : 467.27001953125ms
raycast: : 443.830810546875ms

EDIT 4: @pailhead Here is my plan. 1. find closest grid vertex to point on the plane. I can do a scan of vertex in x/y direction then calculate the min distance. 2. once i have that closest vertex i know that my closest point has to be on a face containing that vertex. So i will find all faces with that vertex using the object.mesh.index.array and calculate the plane to point of each face. Seems like a ray cast should be a little bit smarter than a full scan when intersecting a mesh and at least cull points based on max distance? @WestLangley any suggestions?

EDIT 5: @pailhead thank you for the help. Its appreciated. I have really simplified my example(<200 lines with tons more comments); Is raycaster checking every face? Much quicker to pick out the faces within the set raycasting range specified in the constructor and do a face to point calc. There is no way this should be looping over every face to raycast. I'm going to write my own PlaneBufferGeometry raycast function tonight, after taking a peak at the source code and checking octree. I would think if we have a range in the raycaster constructor, pull out plane buffer vertices within that range ignoring z. Then just raycast those or do a point to plane calculation. I guess i could just create a "mini" surface from that bounding circle and then raycast against it. But the fact that the max distance(manual uses "far") doesn't effect the speed of the raycaster makes me wonder how much it is optimized for planeBuffer geometries. FYI your 300k loop is ~3ms on jsfiddle.

EDIT 6: Looks like all meshes are treated the same in the raycast function. That means it wont smart hunt out the area for a plane Buffer Geometry. Looking at mesh.js lines 266 we loop over the entire index array. I guess for a regular mesh you dont know what faces are where because its a TIN, but a planeBuffer could really use a bounding box/sphere rule, because your x/y are known order positions and only the Z are unknown. Last edit, Answer will be next


Solution

  • The biggest issue resolved is filtering out faces of planeBufferGeometry based on vertex index. With a planeBufferGeometry you can find a bounding sphere or rectangle that will give you the faces you need to check. they are ordered in x/y in the index array so that filters out many of the faces. I did an indexOf the bottom left position and lastIndexOf the top right corner position in the index array. RAYCASTING CHECKS EVERY FACE

    I also gave up on finding the distance from each face of the object and instead used vertical path down the center of the object. This decreased the ray castings needed.

    Lastly I did my own face walk through and used the traingle.closestPointToPoint() function on each face.

    Ended up getting around 10ms per point to surface calculation(single raycast) and around 100 ms per object (10 vertical slices) to surface. I was seeing 2.5 seconds per raycast and 25+ seconds per object prior to optimization.