While testing I found situations where the hit counting was skipping hits due to the step difference added to the ray and other situations where a mesh would get 20,000+ hits recorded and output the wrong value.
It got me thinking about having an option for ray.intersectsMesh(...) to return a complete list of hits instead of just the closest, or to add a separate method to return a list and keep this one returning the closest.
This could be a decent reduction in runtime for an even-odd hit method like in the babylon example, and guarantee the same triangles aren’t getting hit twice by the ray.
Looking at SubMesh._intersectTriangles(...) in SubMesh.ts, it already loops through every face and keeps the closest hit. It seems it would not be that difficult to create an alternate path that returns an array of hits rather than just the closest.
If this makes sense as a feature I would be happy to work on a PR for it, and if so the only question I would have is the expected output of a mesh with multiple submeshes (I would assume an allocation of all hits across all valid submeshes)
If there is any technical reason this wouldn’t work I am also just curious about the logic.
Would it be reasonable to add an optional field to IntersectionInfo for additional hits beyond the closest? That way there is no need for any additional methods or major changes to the existing methods except for a boolean requesting all hits.
I think it would carry up the chain pretty well to Ray.IntersectsMesh as well with minimal bloat.
Some thoughts on code modifications needed for making a generator. This starts at the per mesh level. Later we’ll look at iterating through meshes.
Looking at how intersect is working, the core algorithm is in intersects() withinin AbstractMesh.ts. There is where I would start to modify for a generator. I’ll add to this note as I investigate more. Ultimately, we’ll want to keep the current functionality and add the ability to iterate through the generated intersectInfo objects ourselves.
Once we have a generator on a mesh that yields IntersectInfo, we can duplicate the current functionality with something like:
let currentIntersectInfo;
for (let intersectInfo of this.intersectsGenerator(ray,trianglePredicate,worldToUse)) {
if (!currentIntersectInfo || currentIntersectInfo.distance < intersectInfo.distance)
currentIntersectInfo = intersectInfo;
}
return this.createPickingInfo(intersectInfo, ray, mesh, pickingInfo, worldToUse)
intersectsGenerator() might be able to assume not using onlyBoundingInfo nor skipBoundingInfo.
Inside intersects() from AbstractMesh.ts, separate out the “if (intersectInfo)” on line 2153 into new function createPickingInfo().
The core iteration is using the distance property of intersectionInfo. When a result is selected, pickingInfo is then populated and returned.
pickingInfo from intersectionInfo requires extra calculation and memory, so should probably be avoided within the loop. The extra calculations are
Inputs that need to be retained for creating pickingInfo are
world (Matrix)
ray.origin (from ray parameter)
mesh (“this” in Mesh.intersects())
code:
createPickingInfo(intersectInfo: intersectInfo, ray: Ray, mesh:Mesh, pickingInfo?: PickingInfo, worldToUse?: Matrix): PickingInfo {
pickingInfo = pickingInfo ?? new PickingInfo();
// …fill in the full if (intersectInfo) clause lines 2153 to 2173 …
return pickingInfo;
}
To minimize duplicate code, replace the if clause with:
if (intersectInfo) {
return this.createPickingInfo(intersectInfo, ray, mesh, pickingInfo, worldToUse);
}
Need to work on intersectsGenerator to iterate through submeshes and yield intersectionInfo for all submeshes. Then add the ray intersection code to iterate through meshes.