Issue Detecting Vertices with Bounds
I am trying to create a script that creates a bounding box using Unity's Bounds that will mark all vertices in a mesh that are contained within. So far I have been able to successfully detect vertices within the bounds at the initial point of entry. The problem arises when I try to move either the bounding box or the plane itself. If I move the bounding box, the vertices change, however they are marked opposite to the ones that the box appears to overlap(Photos provided). I also run into an issue where when I move or resize the plane, the vertices do not appear to move with the mesh.
Can anyone see where I am going wrong in the following script? I would like to be able to have this script check and mark vertices within the inspector that are contained within the specified bounds.
This script has been updated as this has been answered
/*
* Created by: Ethan Currah
* Last Updated: 2015/09/11
* Notes: Attach to empty gameobject. Will detect and mark vertices on mesh of all
* objects set as objectsToDecal in inspector that are within the specified Bounds.
*/
#if UNITY_EDITOR
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
public class DecalProjector : MonoBehaviour {
public GameObject[] objectsToDecal;
public Bounds bounds = new Bounds(Vector3.zero, new Vector3(2.2f, 1.0f, 2.2f));
public Color boundsColor = Color.green;
public bool debugVertices = true;
public Color vertexColor = Color.blue;
public bool drawVertGizmos = false;
public float vertGizmoRadius = 0.05f;
private List<Vector3> inboundsVertices = new List<Vector3>();
private Vector3 v3FrontTopLeft;
private Vector3 v3FrontTopRight;
private Vector3 v3FrontBottomLeft;
private Vector3 v3FrontBottomRight;
private Vector3 v3BackTopLeft;
private Vector3 v3BackTopRight;
private Vector3 v3BackBottomLeft;
private Vector3 v3BackBottomRight;
// Unity Lifecycle calls
void Update () {
CalcPositions();
DrawBounds();
CheckVertices(objectsToDecal);
if(debugVertices)
DrawVertices();
}
void OnDrawGizmos()
{
if (drawVertGizmos)
DrawVertexGizmos();
}
// Workhorse Methods
void CalcPositions()
{
bounds.center = transform.position;
//transform.localPosition = transform.InverseTransformPoint(transform.position);
Vector3 v3Center = bounds.center;
Vector3 v3Extents = bounds.extents;
// calculate positions based on bounds
v3FrontTopLeft = new Vector3(v3Center.x - v3Extents.x, v3Center.y + v3Extents.y, v3Center.z - v3Extents.z); // Front top left corner
v3FrontTopRight = new Vector3(v3Center.x + v3Extents.x, v3Center.y + v3Extents.y, v3Center.z - v3Extents.z); // Front top right corner
v3FrontBottomLeft = new Vector3(v3Center.x - v3Extents.x, v3Center.y - v3Extents.y, v3Center.z - v3Extents.z); // Front bottom left corner
v3FrontBottomRight = new Vector3(v3Center.x + v3Extents.x, v3Center.y - v3Extents.y, v3Center.z - v3Extents.z); // Front bottom right corner
v3BackTopLeft = new Vector3(v3Center.x - v3Extents.x, v3Center.y + v3Extents.y, v3Center.z + v3Extents.z); // Back top left corner
v3BackTopRight = new Vector3(v3Center.x + v3Extents.x, v3Center.y + v3Extents.y, v3Center.z + v3Extents.z); // Back top right corner
v3BackBottomLeft = new Vector3(v3Center.x - v3Extents.x, v3Center.y - v3Extents.y, v3Center.z + v3Extents.z); // Back bottom left corner
v3BackBottomRight = new Vector3(v3Center.x + v3Extents.x, v3Center.y - v3Extents.y, v3Center.z + v3Extents.z); // Back bottom right corner
// translate to world coordinates
/* removed as this is already in world coordinates
v3FrontTopLeft = transform.TransformPoint(v3FrontTopLeft);
v3FrontTopRight = transform.TransformPoint(v3FrontTopRight);
v3FrontBottomLeft = transform.TransformPoint(v3FrontBottomLeft);
v3FrontBottomRight = transform.TransformPoint(v3FrontBottomRight);
v3BackTopLeft = transform.TransformPoint(v3BackTopLeft);
v3BackTopRight = transform.TransformPoint(v3BackTopRight);
v3BackBottomLeft = transform.TransformPoint(v3BackBottomLeft);
v3BackBottomRight = transform.TransformPoint(v3BackBottomRight);
* */
}
void CheckVertices(GameObject[] objs)
{
inboundsVertices.Clear();
foreach (GameObject obj in objs)
{
if (obj == null)
continue;
if (obj.activeSelf == false)
continue;
MeshFilter mf = obj.GetComponent<MeshFilter>();
if (mf == null)
continue;
Vector3[] verticesToCheck = obj.GetComponent<MeshFilter>().sharedMesh.vertices;
foreach (Vector3 vertex in verticesToCheck)
{
Vector3 pos = obj.transform.TransformPoint(vertex);
if (bounds.Contains(pos))
{
inboundsVertices.Add(pos);
}
}
}
}
// Methods for Drawing Debug-lines and Gizmos
void DrawBounds()
{
Debug.DrawLine(v3FrontTopLeft, v3FrontTopRight, boundsColor);
Debug.DrawLine(v3FrontTopRight, v3FrontBottomRight, boundsColor);
Debug.DrawLine(v3FrontBottomRight, v3FrontBottomLeft, boundsColor);
Debug.DrawLine(v3FrontBottomLeft, v3FrontTopLeft, boundsColor);
Debug.DrawLine(v3BackTopLeft, v3BackTopRight, boundsColor);
Debug.DrawLine(v3BackTopRight, v3BackBottomRight, boundsColor);
Debug.DrawLine(v3BackBottomRight, v3BackBottomLeft, boundsColor);
Debug.DrawLine(v3BackBottomLeft, v3BackTopLeft, boundsColor);
Debug.DrawLine(v3FrontTopLeft, v3BackTopLeft, boundsColor);
Debug.DrawLine(v3FrontTopRight, v3BackTopRight, boundsColor);
Debug.DrawLine(v3FrontBottomRight, v3BackBottomRight, boundsColor);
Debug.DrawLine(v3FrontBottomLeft, v3BackBottomLeft, boundsColor);
}
void DrawVertices()
{
foreach (Vector3 vertex in inboundsVertices)
{
Debug.DrawLine(vertex + Vector3.down*0.1f, vertex + Vector3.up*0.1f, vertexColor);
Debug.DrawLine(vertex + Vector3.left * 0.1f, vertex + Vector3.right * 0.1f, vertexColor);
Debug.DrawLine(vertex + Vector3.back * 0.1f, vertex + Vector3.forward * 0.1f, vertexColor);
}
}
void DrawVertexGizmos()
{
foreach (Vector3 vertex in inboundsVertices)
{
Gizmos.DrawSphere(vertex, vertGizmoRadius);
}
}
}
#endif
Answer by Bunny83 · Sep 11, 2015 at 07:28 PM
Well, you work on local space vertices while your bounds object seems to represent a world space bounds object.
Furthermore you use transform.TransformPoint but use the vertices of your "objectToDecal". You probably want to use worldspace vertices and you need to use obj.transform.TransformPoint
.
So it might look like this:
void CheckVertices(GameObject obj)
{
inboundsVertices.Clear();
if (obj == null)
return;
MeshFilter mf = obj.GetComponent<MeshFilter>();
if(mf == null)
return;
Vector3[] verticesToCheck = obj.GetComponent<MeshFilter>().mesh.vertices;
foreach (Vector3 vertex in verticesToCheck)
{
Vector3 pos = obj.transform.TransformPoint(vertex);
if (bounds.Contains( pos ))
{
inboundsVertices.Add(pos);
}
}
}
I don't quite understand what you do or intend to do inside your "CalcPositions" method. You again use the transform component of the gameobject this script is attached to to transform positions.
You might want do add more information about in which space your bounds is actually deffined and what exactly you want to do.
Hello and thank you for the fast response.
The object that I attach this to is an empty game object that contains a transform component. I would like for this Bounds object to check within world space whether there are any mesh vertices within it's bounds.
Eventually I would like to attempt to use this information to create a new mesh over "objectToDecal" that fits the bounds, and then apply a material to it.
The calcPositions method is used to calculate the points in which the DrawVertices method needs to be able to draw my bounds. I see now that the bounds are already calculated in World space, so I will remove the section that applies this conversion.
I have since edited my previous script as I noticed what you had mentioned, that I had not been using the mesh's transform for converting to world space.
This appears to have resolved the previous issues, however I think I might have ran into a snag. I'm realizing now that the Bounds.Contains method won't account for any sort of rotation to the bounds, so it may be back to the drawing board.
I will edit my previous script post to ins$$anonymous$$d contain my newer working version.
Please let me know if you are aware of any ways for me to accomplish what it is I am trying to achieve. I am attempting to build this for a college capstone and feel like I might be a little be over my head.
Thank again.
If you need the bounds to be rotated, it's easier to use a second empty gameobject to specify the rotation of your bounds. $$anonymous$$aybe that's already the gameobject this script is attached to?
The Bounds struct always represents an AABB (axis aligned bounding box). Usually those axis are the world axis but when you have a Bounds in local space and the vertices also in the same local space it works again.
So you would define a bounds within the local space of your empty gameobject and you would transfer the vertex positions from the meshes local space to world space and then from world space to the local space of your bounds object. That way you can check the vertex positions with bounds.Contains.
Vector3 pos = obj.transform.TransformPoint(vertex);
if (bounds.Contains( transform.InverseTransformPoint( pos )))
{
Here "pos" still represents the worldspace position but to check with our bounds object we transform them into local space of the object this script is attached to. So the bounds object is relative to this object. If you rotate or move the object you should see a difference.
A decal system usually work on the triangles of the mesh since you just get vertices which are enclosed in your bounds it might get difficult to actually create a new mesh out of them. Usually you need to split the original triangles and create new vertices in between edges which intersect the bounds borders.
However we don't know your final goal of what you want as final result.
Nice, thanks for the tip. I must admit this converting between world and local space business is tricky. I have been able to use your advice however and find a way turn this bounds object from an Axis-aligned Bounding Box (AABB) to an Oriented Bounding Box(OBB).
At the moment my code may not be optimized, as I am still attempting to wrap my head around the use of all these different transform spaces.
As you can see I have been also able to identify the triangles that the mesh vertices belong to. I have found however that this is not a fool proof way of gathering a list all triangles that intersect the bounds. I am ins$$anonymous$$d going to try the approach of implementing Tri-AABB intersection algorithms using the Separating Axis Theorem.
If anyone has any good links that explain this in detail, I would greatly appreciate the assistance.
Thanks in advance!