public sealed class SubObjectPickerWhich face, edge or vertex of one mesh is under the pointer.
Remarks
The third question, and doc 24's B4 is the argument for it. ScenePicker answers "which entity" and PickingBuffer answers it again on the GPU; half of a blockout toolset asks something else — which face of this mesh, within a tolerance measured in pixels, with the innermost element winning. That is the ray test with a different payload rather than a new subsystem, and it is a test against one mesh rather than against a scene, which is why it runs on the processor.
⚠ A face is answered by a ray and a vertex by a projection, and the split is not an inconsistency. A face has area, so the exact question is which triangle the ray through the pointer meets first, and the answer needs no tolerance at all. A vertex has no area and an edge has no width: the only thing that can be asked about them is how near the pointer came on screen, which is on the other side of the projection. So the mesh's positions are projected once per query and the tolerance is in pixels — the same bargain SceneProbe.TryNearestVertex already makes, and for the same reason.
⚠ Innermost wins: a vertex beats an edge and an edge beats a face. Every element within the tolerance is a candidate and the smallest one takes it, because the corner of a face is also on two edges and inside the face, and a rule that took the largest would make a vertex unclickable. It is what every modelling tool does and it is why the tolerance can be generous without making the finer elements unreachable.
⚠ Nothing is occluded, and that is a stated limit rather than an oversight. The vertex on the far side of a cube is as selectable as the one facing you. Fixing it properly means asking what the picture has at a pixel, which is PickingRenderer's id buffer with an element id in it instead of an entity id — the move B4 says this defers — and every cheap approximation in between is a depth bias that is wrong at a silhouette. A block-out mesh is a few hundred elements and its far side rarely projects within ten pixels of its near side; when it does, the nearer of the two wins, which is the case the depth tie-break below is for.
⚠ An instance rather than a static, because this runs on every pointer move. Hover feedback is the thing B4 names as the bar, and it means one query per mouse move for as long as the pointer is over the pane. The projected positions are kept in buffers that grow to the largest mesh asked about and are then reused, so a query allocates nothing.
Fields and properties (1)
public const float DefaultToleranceHow near the pointer has to come to a vertex or an edge, in render pixels.
Methods (2)
public SubObject Under(MeshElements elements, in Matrix4x4 transform, EditorCamera camera, int width, int height, Vector2 pointer, SubObjectFilter filter = All, float tolerance = 10)Which element of a mesh is under a point in the viewport.
public void Within(MeshElements elements, in Matrix4x4 transform, EditorCamera camera, int width, int height, Marquee marquee, MeshElementKind kind, List<int> into)Which elements of a mesh a rubber-band took.
Used by (4)
- ISubObjectPickerVixen.Editor.SceneView
- ScenePickerVixen.Editor.SceneView
- SceneViewportVixen.Editor.SceneView
- SubObjectTestsVixen.Editor.SceneView.Tests