Part of #118145.
For each of the PBVH types, the refactored Relax Face Set brush
performs the following steps:
* Calculate all relevant element factors like other refactored brushes
* Calculate the displacement by performing the following steps, using a
displacement of 0 if certain conditions are unfulfilled (e.g. factor
will have no effect, no relevant neighbor vertices, etc)
* Find all neighbors for each element
* Filter the neighbors based on if the current vert is or is not a
boundary vert, looking at the face sets of each neighbor
* From the relevant neighbors, calculate a smoothed average position.
* For boundary verts, calculate the normal based on the summed
direction towards each neighbor vertex
* For non-boundary verts, retrieve the current vertex normal.
* Use the current position and the retrieved normal to create a
plane.
* Find the closest point on the plane to the smoothed position, use
this as the final displacement
* Apply all of these displacements to the relevant elements
Q: Why do we perform three different parallel loops for each method
instead of a single one like other brushes?
Because much of the processing time for these functions is spent in the
neighbor calculation, we opt to process factors in an earlier loop to
short-circuit neighbor calculation if we know it cannot possibly have
an effect (i.e `factor[i] == 0.0f`)
Q: Why are lambdas used in `filtered_neighbors` ?
Simply put, reducing the overall amount of code duplication,
otherwise this function would require 6 different methods to do the
necessary filtering (boundary vs non boundary vertices for each of the
three pbvh types)
### Potential Areas of Improvement
* Unique face set calculation requires iterating over the
`vert_to_face` map and happens multiple times per brush stroke (each
stroke performs the vertex tasks 4 times in succession). Some form of
cache or precomputed map similar to the `boundary_verts` `BitSpan`
may improve performance.
Pull Request: https://projects.blender.org/blender/blender/pulls/124135