I can find a first nearest point. How can I find a second nearest point?
PS: The screenshot is from Blender 3.2. Feel free to use any Blender version.
I can find a first nearest point. How can I find a second nearest point?
PS: The screenshot is from Blender 3.2. Feel free to use any Blender version.
The functionality of octrees in Geometry Nodes is quite limited and so basically for problems like that you need an all-to-all interaction like here, and the problem is actually conceptually similar to:
Geometry Nodes: How to find the 2 vertices that are furthest apart?
So here's how I implemented this using a 'geometry explosion':
Imgur mirror (SE image hosting has problems)
"Which Nearest?" is simply $2$ to answer OP's question, but could be any number. I don't check if it's not too big.
For clarity, the Grid geometry (called "Target" in Takapapatapaka's answer) is colored dark blue when it's in its original form, bright blue when it is exploded, and black when all points but winners are removed (the domain size returns to original, but it's a different geometry in nature hence black not dark blue).
The logic should be clear: Duplicate the "Target" geometry, the grid, as many times as the number of points ("Source") seeking the 2nd nearest. Now there's one duplicate for each "Source" point, and each such duplicate is sorted by distance to the relevant "Source" point. Then to get only the nearest points, you would get the 1st result for each grid, but that makes no sense as "Vanilla Functionality" already does that much more efficiently. But you can take 2nd result for each grid for 2nd nearest, 3rd result for 3rd nearest etc.
Since for each duplicate grid I'm leaving behind only a single vertex, and the order of grids was the order of relevant points, the mapping of "Source" point to "Target" vertex is 1:1. If you wanted to simultaneously calculate e.g. 2nd and 3rd nearest, the right-most "Sample Index: Index" logic would change.
This solution should be faster than takapakapaka's answer, but sadly despite not using a repeat zone the timing is well over 50% of his.
The performance bottleneck in the solution above is clearly the sorting. So below is a solution that deletes the 1st nearest, and then again searches for the nearest point. The problem is, because 1st nearest is different for each point, you still need geometry explosion to have a separate copy for each sampling ("Source") point. Then "Sample Nearest" doesn't provide a way to separate geometry into groups, therefore I temporarily join the exploded geometry with sampling points (and mark that geometry with cyan color) and use "Index of Nearest" which provides such functionality:
This is slower than the 1st solution, now very close to takapakatapapaka's answer in performance. The new, worse bottleneck is the "Index of Nearest" which creates a separate octree for each group and apparently that's slower than sorting. If you think you could use a single octree by offsetting duplicates - I tried it, and the "Sample Nearest" reported much worse performance (~5 times slower, see the file).
v.4.4.0.
Not sure if this is okay to unearth an old thread, but I found it while searching for the same thing, and it put me on the way of a solution not detailed anywhere else, so I thought it might be useful anyway.
I originally was trying to achieve something via Delete Geometry, but it would require to have a duplicate of the target geometry for each element in the source geometry. Searching for a way to achieve this, I found the Repeat Zone.
New (4.0) node Repeat Zone makes a quite simple solution to this problem, though it may be computationally intensive. Simply put, it enables us to iterate over all elements of the target geometry, and store them if they are closer than the previous ones. Since we have a hand in the iteration, we can make it so it does not store only the closest, but also the second closest.
This kinda is brute force iteration, and there is not much optimization in my solution, so it is slow (around half a second on my machine) for the configuration provided in this question (comparing 1k points against a grid of ~10k vertices). For comparison, the node tree proposed in the question takes only 2ms on my machine. So its applicability may vary depending on the amount of geometry you need to use.
Here is a screenshot of my setup, along with the blendfile with multiple setups (see below for the different options) : 
If the indexes are starting from 0 and there is no gap in their progression, it should give the correct amount of elements. From what I know, geometry nodes recalculates indices when changes are made (like deleting some geometry), so apart from inputing external geometry (as in edited by hand or created in another program) which has weird indexes, it should be relatively safe to use. If it had weird indexes, it possibly could try to reach for way too many elements, which could lead in longer process time or crash if memory runs out. 2. In the Repeat Zone, retrieve the indexes of the current element, the first closest and second closest, and calculate their distance to the source geometry position property. 3. Compare the distances, giving 3 options according to the state of the current element :
I tried various set-ups to optimize the process time, see below for a list of my attempts. Some keypoints :
| Attempt | Time | w/o Reroute | Description |
|---|---|---|---|
| Storing results as Repeat Items | 800ms | 660ms | Using the Repeat Zone inputs/outputs to store the nearest points, and assigning them to Attributes afterwards |
| Using switch before Store Attributes | 550ms | 410ms | Using Store Attributes inside the Repeat Zone and a set of switches beforehand to decide what to store (either re-storing the previous one, either storing the current element if closer) |
| Using the selection input of Store Attributes | 460ms | 320ms | Selecting only the new values when storing attributes, with a single switch for the 2nd Nearest |
| Using 3 Store Attributes instead of 2 | 430ms | 340ms | (current solution) Duplicating the 2ndNearest Store Attribute node, one in case the current element is closer than the 2nd only, and one in case it's closer than both |
| Using boolean logic to avoid overwriting | 450ms | 400ms | (inefficient) Using a Not->And boolean nodes before the first 2ndNearest Store Attribute, to avoid storing it 2 times in some cases |
| Storing distance of 1st and 2nd closest | 450ms | 370ms | (inefficient) Storing as attributes the distance to the current 2 closest point, to avoid re-calculating it multiple times |
Problem in other answer
This issue recently came up for me as well, and since I had to deal with it, I'd like to share my approach! I'm adding this response because when trying to understand the previous approach, I identified a problem. The Sample Nearest node is actually receiving the original mesh and not the generated points, which causes it to return incorrect values. I've included a screenshot showing this issue.
If you analyze point "0", you'll see it returns "101" as the closest, but in reality it should be point "13".
Regarding my approach:
I used the 'For Each Element' to calculate the nearest point using Sample Nearest, but it was always returning the same point as the closest one.
I needed to make it "self-ignore" in each loop. Then, since I was going to delete the mesh, I needed to save the original indices, as GN always recalculates them (as others have mentioned).
I chose to store them as an ID for convenience, but it could be any attribute.
Next, I could use Sample Nearest and use the ID to transfer this information to my current point, with the Sample Index and store it as an attribute.
After that, I just repeated this logic, but now I also needed to delete the "First Nearest" from my verification, which allowed me to find the Second Nearest."