Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by DayyanSisson · Jan 03, 2013 at 08:13 PM · meshperformanceverticeswhile

Alternative Ways of Finding Vertices

I know one way of finding vertices that meet a certain criteria is to run a while loop through a mesh's vertices and use if statements to see which ones meet the criteria, but if there are extremely large amounts of vertices, this could be extremely taxing. For example, if I wanted to see whether certain vertices were within a certain distance from an object, or were within another object's bounds, I would have to do this:

 int i = 0;
 while(i < vertices.Length){
     if(otherCollider.bounds.Contains(vertices[i])){
          //blah blah
     }
 }

(Note: Yes I'm aware that that bit of code wouldn't actually work, but you get the idea)

And if the mesh had 4000 vertices, it would run pretty slow. So what else could I do to find these same vertices?

Edit:

Here's the code at hand if anyone would like to see it (refer to comment thread in one of the answers):

 public class TerrainEditorLayer {
 
     public string name = "New Layer";
     public string layerTag = "Layer Tag";
 
     public Transform terrainLayer;
 
     public float layerHeight = 0;
     public Vector2 terrainSize = new Vector2(10,10);
 
     public Texture baseTexture;
     public Texture paintTexture;
 }
 
 public class TerrainEditor : MonoBehaviour {
 
     public List<TerrainEditorLayer> layers;
 
     public Collider brush;
 
     public float brushSize = 100;
     public float opacity = 100;
 
     public bool continuous;
     public bool smooth;
     private bool digTool;
 
     public int terrainLayer;
     private int layerMask;
 
     private RaycastHit hit;
     private Collider[] sHit;
     private Collider other;
 
     private Transform finder;
     public Transform brushProjector;
 
     void Awake () {
 
         layerMask = 1 << terrainLayer;
         finder = transform;
     }
 
     void Start () {
 
         foreach(TerrainEditorLayer layer in layers){
             layer.terrainLayer.tag = layer.layerTag;
             layer.terrainLayer.position = new Vector3(0, layer.layerHeight, 0);
         }
     }
 
     void Update () {
 
         if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)){
             digTool = true;
         }else{
             digTool = false;
         }
 
         if(continuous){
             if(Input.GetButton("Fire1")){
                 if(Physics.Raycast(finder.position, finder.forward, out hit, 1000)){
                     foreach(TerrainEditorLayer layer in layers){
                         if(hit.collider.tag == layer.layerTag){
                             if(brush){
                                 brush.transform.position = hit.point;
                             }
                             Deform(layer, FindNextLayer(layer));
                         }
                     }
                 }
             }
         }else{
             if(Input.GetButtonDown("Fire1")){
                 if(Physics.Raycast(finder.position, finder.forward, out hit, 1000)){
                     foreach(TerrainEditorLayer layer in layers){
                         if(hit.collider.tag == layer.layerTag){
                             if(brush){
                                 brush.transform.position = hit.point;
                             }
                             Deform(layer, FindNextLayer(layer));
                         }
                     }
                 }
             }
         }
     }
 
     void Deform (TerrainEditorLayer currentLayer, TerrainEditorLayer nextLayer) {
 
         sHit = Physics.OverlapSphere(hit.point, (brushSize/100), layerMask);
         foreach(Collider terrain in sHit){
             if(terrain.GetComponent<MeshFilter>() && terrain.CompareTag(currentLayer.layerTag)){
                 Mesh mesh = terrain.GetComponent<MeshFilter>().mesh;
                 Vector3[] terrainVertices = mesh.vertices;
                 Vector3[] terrainNormals = mesh.normals;
 
                 Vector3 vertPoint = terrain.transform.InverseTransformPoint(hit.point);
 
                 int i = 0;
                 while(i < terrainVertices.Length){
                     if((terrainVertices[i] - vertPoint).magnitude < (brushSize/10)){
                         Vector3 digDir = new Vector3(0,0,0);
                         if(digTool){
                             digDir = terrain.transform.TransformDirection(Vector3.up);
                         }else{
                             digDir = terrain.transform.TransformDirection(-Vector3.up);
                         }
                         Vector3 vertMove = new Vector3(0,0,0); 
                         if(smooth){
                             if(digTool){
                                 digDir = terrain.transform.TransformDirection(Vector3.up);
                                 vertMove = digDir * ((opacity/100) * Time.deltaTime) + (terrainNormals[i]/-100);
                             }else{
                                 digDir = terrain.transform.TransformDirection(-Vector3.up);
                                 vertMove = digDir * ((opacity/100) * Time.deltaTime) + (terrainNormals[i]/100);
                             }
                             terrainVertices[i] += vertMove;
                         }else{
                             if(digTool){
                                 digDir = terrain.transform.TransformDirection(Vector3.up);
                                 vertMove = digDir * ((opacity/100) * Time.deltaTime);
                             }else{
                                 digDir = terrain.transform.TransformDirection(-Vector3.up);
                                 vertMove = digDir * ((opacity/100) * Time.deltaTime);
                             }
                             terrainVertices[i] += vertMove;
                         }
                     }
                     i++;
                 }
 
                 mesh.vertices = terrainVertices;
                 mesh.RecalculateBounds();
                 mesh.RecalculateNormals();
                 terrain.transform.GetComponent<MeshCollider>().enabled = false;
                 terrain.transform.GetComponent<MeshCollider>().sharedMesh = mesh;
                 terrain.transform.GetComponent<MeshCollider>().enabled = true;
             }
         }
     }
 
     TerrainEditorLayer FindNextLayer (TerrainEditorLayer currentLayer) { 
 
         float closestDepth = Mathf.Infinity;
         TerrainEditorLayer closestLayer = new TerrainEditorLayer();
 
         foreach(TerrainEditorLayer layer in layers){
             if((currentLayer.layerHeight - layer.layerHeight) > (currentLayer.layerHeight - closestDepth)){
                 closestDepth = layer.layerHeight;
                 closestLayer = layer;
             }
         }
 
         return closestLayer;
     }
Comment
Add comment · Show 8
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image reptilebeats · Jan 03, 2013 at 09:13 PM 0
Share

i havent played around with verticles but could you not find the vertical to begin with and save it as a varible, then access it when needed ins$$anonymous$$d of searching for it at run time.

avatar image DayyanSisson · Jan 03, 2013 at 09:57 PM 0
Share

Well in my case, I only need to access the vertices during runtime, and the vertices that need to be accessed could be different every time.

avatar image reptilebeats · Jan 03, 2013 at 10:10 PM 0
Share

what you could do then is divide the objects verticles into smaller groups. so then if you hit something it will only search the verticles assigned to that area.

avatar image DayyanSisson · Jan 03, 2013 at 10:28 PM 0
Share

Yeah thats the current approach I'm trying, but I'm hoping to find another way. The problem is when you split an object up, you get more draw calls as it renders each object separately. What I was hoping to do was edit each of the mesh's vertices, and once thats done, create a new mesh using those vertex coordinates for all of the mesh's, and then render that mesh. In that way, their will be 4 separate mesh's but it will render them as a whole. I can't seem to do that though.

avatar image alexfeature · Jan 03, 2013 at 10:35 PM 0
Share

It seems like you are trying to simply merge the meshes together into one. That's what CombineChildren script form Unity's StandardAssets does if I'm not mistaken.

Have a look at that.

Also, if I'm not mistaken doing something like this has limitations such as number of vertices per mesh, single material and so on.

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by alexfeature · Jan 03, 2013 at 09:22 PM

I don't have anything constructive to suggest code wise but I would like to say that unless you try stuff you will not actually know how fast or slow something is.

I recall reading somewhere on the main unity site (I think David H. said this) that Unity arrays are extremely fast and that Unity is capable of looping through upwards of 1 million vertices per second or something like that. Can't remember the actual numbers now.

Regardless, 4k array of VectorX's is no resource hog by any stretch of imagination.

I'm not good at algebra, let alone geometry, but I would imagine checking a bounding box against a bounding box is far more efficient. Building a virtual bounding grid around complex meshes (think culling grids for occlusion calculations) would greatly reduce the number of checks you would need to do.

Maybe someone a bit more experienced in this area will be able to suggest a better approach.

Just my 2 cents.

Comment
Add comment · Show 22 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DayyanSisson · Jan 03, 2013 at 09:55 PM 0
Share

If it was 1 million vertices per second, I would have no problem at all. I was getting performance hits somewhere around 600+ vertices.

avatar image alexfeature · Jan 03, 2013 at 10:18 PM 0
Share

Sounds odd, I find it a bit hard to believe. Of course it all depends on what exactly you are checking for besides the contains bit.

I would imagine accessing any property such as .transform.xxx would cause unnecessary overhead .

Also, going through all the vertices from beginning to end seems redundant.

What exactly is your usage scenario? Perhaps there is a point of reference that can reduce the scope of your search?

avatar image Julien-Lynge · Jan 03, 2013 at 10:21 PM 1
Share

Things are drastically, drastically slower if you try to access the vertices directly from the mesh every time. Not sure what you're doing, but you should be grabbing a copy of the verts and looping through that:

 Vector3[] verts = mesh.vertices;
 for (int i = 0; i < verts.length; i++)
     do something...

if you're currently looping through the mesh.vertices every time, that should speed things up by a factor of a hundred to a thousand.

Same for transforms, as alex mentioned.

avatar image Julien-Lynge · Jan 03, 2013 at 10:35 PM 1
Share

Then your overhead has to be in checking against the bounding box - $$anonymous$$d posting that code? Accessing 600 vertices from the list should be sub-millisecond time. Are you doing anything like converting from local to world space on each vertex?

Also, are you going to be accessing the vertices multiple times over the course of your game? If you're not memory constrained, you could build some additional data structures to, for instance, hold the indices of vertices organized by their X, Y, and Z position, and use that to decrease the amount of computation at check time.

avatar image Julien-Lynge · Jan 04, 2013 at 12:11 AM 1
Share

So that sounds like about 3 ms of increase. Not huge, but definitely noticeable. I wonder, though, how much of that is co$$anonymous$$g from defor$$anonymous$$g the mesh, how much from running the calcs, etc.

You can use System.Diagnostics.Stopwatch to time the actual calculations and get a more exact feel for how long things are taking. Try creating a new Stopwatch, and then calling Start() where you want to start, Stop() after you do your calculations, and elapsed$$anonymous$$illiseconds (or elapsedTicks) to see how long things are taking. That should help you find where the bottlenecks are.

Show more comments
avatar image
0

Answer by PaulR · Jan 07, 2013 at 11:03 AM

You want to:

  • Cache "`terrain.transform.TransformDirection(Vector3.up)`" etc... - No need to recalculate that for each vertex in range

  • Change this "`(terrainVertices[i] - vertPoint).magnitude < (brushSize/10)`" to use sqrMagnitude. You're doing a sqrt per vertex.

  • Cache this too "`((opacity/100) * Time.deltaTime)`" since it's constant for the loop

  • You could refactor your loop to remove a bunch of branches. Eg, have 1 loop for when smooth is on, and one for when it's off. It doesn't change during the loop so no need to check it each time. So you'd end up with 4 loops:
    • smooth && dig

    • smooth && !dig

    • !smooth && dig

    • !smooth && !dig

  • Remove this "`Vector3 digDir = new Vector3(0,0,0);`" - since you're just overwriting the value after anyway

  • Move "'Vector3 vertMove = new Vector3(0,0,0); '" out of the loop

Obviously, measure performance before and after each change, and make sure it is actually quicker, etc.. - So you should end up with something like (untested):

 foreach(Collider terrain in sHit)
  {
     if(terrain.GetComponent<MeshFilter>() && terrain.CompareTag(currentLayer.layerTag))
     {
         Mesh mesh = terrain.GetComponent<MeshFilter>().mesh;
         Vector3[] terrainVertices = mesh.vertices;
         Vector3[] terrainNormals = mesh.normals;
 
         Vector3 vertPoint = terrain.transform.InverseTransformPoint(hit.point);
         Vector3 vertMove;
         Vector3 digDir;
 
   
         int i = terrainVertices.Length;
         float sqrdBushSize = (brushSize/10.0f) * (brushSize/10.0f);
         float strength = ((opacity/100) * Time.deltaTime);

         if(digTool)
            digDir = terrain.transform.TransformDirection(Vector3.up) * strength;
          else
            digDir = terrain.transform.TransformDirection(-Vector3.up) * strength;
         
         switch( (smooth?1:0) + (digTool?2:0) )
         {
             case 0:    // !smooth && !digTool
                 while(--i)
                 {
                     if( (terrainVertices[i] - vertPoint).sqrMagnitude > sqrdBushSize) 
                         continue;
                    terrainVertices[i] += digDir;
                  }
              break;
             case 1:    // smooth && !digTool
                 while(--i)
                 {
                     if( (terrainVertices[i] - vertPoint).sqrMagnitude > sqrdBushSize) 
                         continue;
                    terrainVertices[i] += digDir + (terrainNormals[i] * 0.01f);
                  }
              break;
             case 2:    // !smooth && digTool
                 while(--i)
                 {
                     if( (terrainVertices[i] - vertPoint).sqrMagnitude > sqrdBushSize) 
                         continue;
                    terrainVertices[i] += digDir;
                  }
              break;
             case 3:    // smooth && digTool
                 while(--i)
                 {
                     if( (terrainVertices[i] - vertPoint).sqrMagnitude > sqrdBushSize) 
                         continue;
                    terrainVertices[i] += digDir + (terrainNormals[i] * 0.01f);
                  }
              break;
         }
     }
 }
Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DayyanSisson · Jan 11, 2013 at 02:31 AM 0
Share

Doesn't make a significant difference but makes feel stupid for not doing all of that in the first place. Thanks!

avatar image Dessix-Machina · Nov 11, 2013 at 01:41 AM 0
Share

Breaking concise loops into multiplicity to benefit performance is the compiler's job, and the effect on readability and maintainability may be worse than the $$anonymous$$or gain granted in performance. Branches aren't very heavy in this sort of system, and they're orders of magnitude below the cost of the most expensive operations; as such I'd focus on structure rather than micro-optimizations.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

12 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

mask one gameObject mesh by another mesh vertex transparency 1 Answer

Vertex Color index problem 1 Answer

Why does my mesh's vertices all set to 0 when I try to access it using Mesh.vertices? 1 Answer

Mesh adaption 1 Answer

Edit SkinnedMeshRenderer 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges