- Home /
Finding locations of Vertices on a Mesh
Hi there,
I'm trying to find the bounding box around a user-specified mesh and eventually generate a cube that matches this bounding box in dimensions and location. The script yields no errors and seems to be calculating something, but the results it gives me don't make sense. I have a model that is registering as having widths in the .001 range, but when I actually look at the mesh's stats it should be around 1. Is this a problem with my algorithm or is there no connection between the positions of vertices and the position of the model itself in the world space? Thank you for your help!
Answer by Bunny83 · Aug 07, 2012 at 01:32 AM
I'm still not sure what you actually want. When you talk about the bounding box, why do you calculate the bound manually? Unity provides two different bounding boxes. The Mesh class provides a local space AABB of the mesh and the Renderer provides a world space AABB.
I've posted a script that visualizes those two bounding boxes in a comment to my answer on this question.
edit
Just to simplify your code a bit and to clear up some things ;)
It doesn't make much sense to pass the models variable to a member function. If it should be a "standalone function" it should be static. In this case it would make sense to pass the required gameobject.
It's a bit confusing that you use the indexer of Vector3 but you still access each component (x,y,z or 0,1,2) seperately.
Most math operations are also possible with Vector3 structs, so there's no need to perform everything seperately for each component.
Your bounding box is, like Aldo said, in local space. It you want it in world-space you need to convert it with TransformPoint
Here's a modified version of your script. The actual calculations is simplified and i've added some obvious error checks.
public class cubify : MonoBehaviour
{
public GameObject model;
void Start()
{
CreateBoundingCube();
}
void CreateBoundingCube()
{
Bounds bBox = CalculateBoundingBox(model);
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = bBox.center;
cube.transform.localScale = bBox.size;
}
public static Bounds CalculateBoundingBox(GameObject aObj)
{
if (aObj == null)
{
Debug.LogError("CalculateBoundingBox: object is null");
return new Bounds(Vector3.zero, Vector3.one);
}
Transform myTransform = aObj.transform;
Mesh mesh = null;
MeshFilter mF = aObj.GetComponent<MeshFilter>();
if (mF != null)
mesh = mF.mesh;
else
{
SkinnedMeshRenderer sMR = aObj.GetComponent<SkinnedMeshRenderer>();
if (sMR != null)
mesh = sMR.sharedMesh;
}
if (mesh == null)
{
Debug.LogError("CalculateBoundingBox: no mesh found on the given object");
return new Bounds(aObj.transform.position, Vector3.one);
}
Vector3[] vertices = mesh.vertices;
if (vertices.Length <=0)
{
Debug.LogError("CalculateBoundingBox: mesh doesn't have vertices");
return new Bounds(aObj.transform.position, Vector3.one);
}
Vector3 min, max;
min = max = myTransform.TransformPoint(vertices[0]);
for (int i = 1; i < vertices.Length; i++)
{
Vector3 V = myTransform.TransformPoint(vertices[i]);
for (int n = 0; n < 3; n++)
{
if (V[n] > max[n])
max[n] = V[n];
if (V[n] < min[n])
min[n] = V[n];
}
}
Bounds B = new Bounds();
B.SetMinMax(min, max);
return B;
}
}
Keep in mind that this will calculate the real AABB in worldspace at the current state. When the object moves or rotates you have to recalculate the boundingbox. That's why unity stores the boundingbox in local space and just calculates the worldspace boundingbox of the local rotated bounding box. Otherwise you would have to iterate through all vertices every frame since there's no other way to calculate the true AABB of an object.
@Bunny83, does the renderer.bounds encapsulate only the mesh vertices or the mesh bounding box (converted to world space, of course)? This may make a big difference for long objects!
Renderer.bounds will encapsulate the rotated mesh bounds. That's why the bounds are usually a bit larger than the true bounding box. I've posted this picture in one of my comments of that question i've linked:
That's why meshes shouldn't be aligned along the local axis, so the $$anonymous$$esh.bounds fits the mesh best.
Hi, I am also trying to find vertices within a bounds object but am experiencing some odd behavior. I'm hoping that someone with a better grasp of this topic might be able to help me with the following: http://answers.unity3d.com/questions/1065170/issue-detecting-vertices-with-bounds-1.html Thanks in advance :)
Answer by aldonaletto · Aug 07, 2012 at 01:45 AM
Vertices are in model space - no scale, position or rotation is taken into account. In order to evaluate the bounding box in world space, you should convert each vertex like this:
...
Vector3 worldVert = model.transform.TransformPoint(vertices[i]);
if (worldVert.x > highestXValue){
highestXValue = worldVert.x;
}
if (worldVert.x < lowestXValue){
lowestXValue = worldVert.x;
}
...
But you don't need to waste time and effort calculating this: the property *renderer.bounds* already contains the object's bounding box in world coordinates (Unity needs it for frustum culling). If you want the bounding box in your Vector3[] format, just convert it:
private Vector3[] findBoundingBox(GameObject model){ Vector3[] boundingBox = new Vector3[2]; boundingBox[0] = model.renderer.bounds.min; boundingBox[1] = model.renderer.bounds.max; return boundingBox; }
Answer by ekofman · Aug 07, 2012 at 05:14 PM
Thanks for your help everybody, good to know that the renderer.bounds and mesh.bounds properties exists, that should make things a little easier. However, I did find a way to fix the problem I had by just multiplying the coordinates by the scaling of the mesh (the coordinates my algorithm yielded apparently only were related to the space that 1:1:1 scaling of the mesh would have filled).
highestXValue = highestXValue * model.transform.localScale.x;
highestYValue = highestYValue * model.transform.localScale.y;
highestZValue = highestZValue * model.transform.localScale.z;
lowestXValue = lowestXValue * model.transform.localScale.x;
lowestYValue = lowestYValue * model.transform.localScale.y;
lowestZValue = lowestZValue * model.transform.localScale.z;
Thanks again for your quick responses.
If you plan to encapsulate the model inside a cube, remember to copy the model rotation/position to the cube.
Your answer
Follow this Question
Related Questions
Why does my object disappear? 1 Answer
How to visualize Object with precise Size and Position 0 Answers
Underwaterview 1 Answer
Position and scale GameObject according to screen size 2 Answers
Wheelcolliders bug ? 1 Answer