- Home /
Make Vertices selectable and shown as UI
Hi,
I have a setup where I have a mesh which has editable vertices directly in game. Each vertex's position on screen is calculated in OnGUI() to display a GUI.Button that makes it selectable. Selection can also be made through a marquee selection, but the rest does not matter.
The real problem is - you guessed it - that the GUI is painstakingly slow and makes the whole thing super laggy. I wondered how I could get it done more efficiently - maybe through the more recent UI system, though I'd prefer not to for legitimate and uselessly precise reasons - or otherwise.
Answer by andrew-lukasik · Oct 04, 2021 at 06:12 AM
Creating thousands of UI elements to represent all the mesh vertices just to make them selectable is a bad idea. Full stop.
Drop it and move forward with something much more simple, reliable and performant. The very first thing you should try is to just calculate vertex selection 100% manually.
How to do that? Just iterate over all vertices and look for Ray
& sphere or screen point & Rect
intersections on mouse click. If performance starts to be the issue for some reason - no worries, there is plenty of space for optimizations here (AABB sets, hierarchies etc).
using UnityEngine;
[RequireComponent( typeof(MeshFilter) , typeof(MeshRenderer) )]
public class LetsSelectMeshVertices : MonoBehaviour
{
[SerializeField] Camera _camera;
[SerializeField] float _hotSpotSize = 30f;
[SerializeField] int _selectedVertexIndex = -1;
Vector3[] _vertices;
void Start ()
{
_vertices = GetComponent<MeshFilter>().sharedMesh.vertices;
}
void OnBecameVisible () => enabled = true;
void OnBecameInvisible() => enabled = false;
void Update ()
{
if( Input.GetMouseButtonDown(0) )
{
Vector2 mousePosition = Input.mousePosition;
Matrix4x4 ltw = transform.localToWorldMatrix;
for( int vertexIndex=_vertices.Length-1 ; vertexIndex!=-1 ; vertexIndex-- )
{
Vector3 vertexWorldPos = ltw.MultiplyPoint3x4( _vertices[vertexIndex] );
Vector3 vertexScreenPos = _camera.WorldToScreenPoint( vertexWorldPos );
Rect vertexScreenRect = new Rect( vertexScreenPos.x-_hotSpotSize*0.5f , vertexScreenPos.y-_hotSpotSize*0.5f , _hotSpotSize , _hotSpotSize );
if( vertexScreenRect.Contains(mousePosition) )
{
_selectedVertexIndex = vertexIndex;
return;
}
}
_selectedVertexIndex = -1;
}
}
#if UNITY_EDITOR
void OnDrawGizmos ()
{
Matrix4x4 ltw = transform.localToWorldMatrix;
if( _vertices!=null )
for( int vertexIndex=_vertices.Length-1 ; vertexIndex!=-1 ; vertexIndex-- )
{
Vector3 vertexWorldPos = ltw.MultiplyPoint3x4( _vertices[vertexIndex] );
Gizmos.color = Color.blue;
Gizmos.DrawSphere( vertexWorldPos , 0.05f );
}
if( _selectedVertexIndex!=-1 )
{
Gizmos.color = Color.red;
Gizmos.DrawSphere( ltw.MultiplyPoint3x4(_vertices[_selectedVertexIndex]) , 0.05f );
}
}
#endif
}
Your answer
Follow this Question
Related Questions
UnityEngine.UI.Text characters mesh 0 Answers
Color triangle on mesh 3 Answers
Finding lowest point of a mesh 0 Answers
How do I get vertex positions of the referenced game object, and not its mesh? 2 Answers