- Home /
Why is my vertex array empty using GetComponent().mesh.vertices?
I am trying to identify the closest vertex to the mouse click on my object. I have used the following code:
public void OnMouseDown()
{
Vector3[] vertex = GetComponent<MeshFilter>().mesh.vertices; // why does this come back empty?
Debug.Log(vertex);
}
I have tested the code and on the console I am getting something printed, but just an empty Vector3 rather than with any components. I can't figure out why it would be empty.
What does the debug print out exactly? $$anonymous$$aybe it isn't empty, but arrays have a very basic ToString()
, it just prints the type. Try this debug printout:
if (vertex == null) { Debug.Log("Vertex: null!"); }
else { Debug.Log("Vertex: " + vertex + ", length: " + vertex.Length); }
Optionally, you could try to go more carefully:
$$anonymous$$eshFilter meshFilter = GetComponent<$$anonymous$$eshFilter>();
if (meshFilter == null) { Debug.Log("$$anonymous$$eshFilter not found!"); return; }
else if (meshFilter.mesh == null) { Debug.Log("$$anonymous$$eshFilter does not have a mesh!"); return; }
else {
Vector3[] vertex = meshFilter.mesh.vertices;
if (vertex == null || vertex.Length < 1) { Debug.Log("Could not get vertices from mesh!"); return; }
// do here what you want to do
}
This is what is printed: UnityEngine.Vector3[] UnityEngine.Debug:Log(Object)
Trying your first if statement, I get a length, but it's not what I'm expecting...I'm hoping for a vector location: Vertex: UnityEngine.Vector3[], length: 44071 UnityEngine.Debug:Log(Object)
Trying your second more careful option, I end up with the same result as the way I was doing it - a see$$anonymous$$gly empty vector.
O$$anonymous$$, so there is no problem with your mesh, you do get the vertices of your mesh, of which there are 44071.
What do you mean by "hoping for a vector location"? Do you want to get the position of each vertex? Something like this?
// warning, this will take a while to print!
for (int i = 0; i < vertex.Length; ++i) { Debug.Log("vertex " + i + ": " + vertex[i]); }
Answer by Harinezumi · Apr 04, 2018 at 12:37 PM
From a comment of the question, shrutiturner "would like to make a function that gives me the vector location of the nearest vertex to the mouse click."
There are multiple ways of doing this, but you will have to use a raycast and a collider for it either way.
The simpler way is that you get the triangle the raycast hit, then select the vertex closest to the hit point. Unfortunately getting the triangle index only works if you use a MeshCollider on your object. Something like this:
RaycastHit hit;
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit)) {
int triangleIndex = hit.triangleIndex;
MeshFilter meshFilter = GetComponent<MeshFilter>();
Mesh mesh = meshFilter.mesh;
// getting the vertices of the triangle; mesh.triangles contains the indices to the vertices
Vector3 a = mesh.vertices[mesh.triangles[3 * triangleIndex + 0]]; // +0 is not needed, I just want to make it clear
Vector3 b = mesh.vertices[mesh.triangles[3 * triangleIndex + 1]];
Vector3 c = mesh.vertices[mesh.triangles[3 * triangleIndex + 2]];
Vector3 localA = hit.transform.TransformPoint(a);
Vector3 localB = hit.transform.TransformPoint(b);
Vector3 localC = hit.transform.TransformPoint(c);
float distanceToA = Vector3.Distance(localA, hit.point);
float distanceToB = Vector3.Distance(localB, hit.point);
float distanceToC = Vector3.Distance(localC, hit.point);
// sorry for the confusing ternary operator chain, but I don't have much time
Vector3 closestVertexToMouseCursor = distanceToA < distanceToB ? distanceToA < distanceToC ? a : c : distanceToB < distanceToC ? b : c;
The other approach transforms the hit point into the local space of the mesh, then iterates through all vertices of the mesh to find the closest one. I think it is much less efficient, so I will not make the effort of writing it down.
This is perfect! Exactly what I was looking for. Thank you so much for all your time and explanations - I really appreciate it :)
$$anonymous$$eep in $$anonymous$$d that the triangle index will only be set if you use a $$anonymous$$eshCollider. Any primitive collider (sphere, box, capsule) does not have any connection to the underlying mesh and won't return a UV coordinate or a triangle index in the hit.
Also you may want to use Collider.Raycast ins$$anonymous$$d of Physics.Raycast. It's a bit cheaper and will ignore all other colliders.
Finally the triangleIndex is not an index into the triangles array. You have to multiply it by 3 to get the index of the first vertex reference. So the 3 points are triangleIndex*3 + 0
, triangleIndex*3 + 1
and triangleIndex*3 + 2
ps: Ohh another mistake ^^. hit.point
is a worldspace position while the vertices inside the vertices array are localspace positions. You either need to transform the 3 vertices into worldspace or the hit.point into localspace before you can do any distance calculations. You may want to have a look at the example on the triangleindex page
Oops, you are right! I was writing it off the top of my head, and messed up with triangleIndex
and hit.point
. I will update my answer.
Also, I didn't even know about Collider.Raycast
... :O
@Harinezumi - thanks I got your explanation about the triangle*3 via email but can't seem to find the answer on screen! It makes perfect sense.
Answer by tormentoarmagedoom · Apr 04, 2018 at 09:39 AM
What version of unity are you using? It should be working... Is strange because if object does not have a mesh, you will recieve the error message, but if dont recieve it is becaise there is a mesh. And a mesh with no vertices i supose is imposible....
I'm using the latest I think, I downloaded it only last week: Unity 2017.4.0f1
I'm sorry but i dont see why is this happening. What kind of mesh is the object? Try some things like find a single vertex, or try to do it with some other object to see if is thw object or the code... Or find another way to get what ypu need like create manually emptyobjects at the vertices.
I've tested it on my own object and one of the Unity default cubes and have the same issue, unfortunately.
Answer by FlaSh-G · Apr 04, 2018 at 11:39 AM
As you stated in the question comments, you get UnityEngine.Vector3[]
which means "an array of Vector3", nothing more and nothing less. Your Debug.Log output does not say anything about the number of Vector3 in that array, so from the output, you can't even tell whether the array is empty or not.
As @Harinezumi already hinted at, to print further information, you need to change your Debug.Log line:
Vector3[] vertices = GetComponent<MeshFilter>().mesh.vertices;
Debug.Log(vertices.Length + " vertices are in that array.");
for(var i = 0; i < vertices.Length; i++)
{
Debug.Log("Vertex #" + i + " is " + vertices[i]);
}