Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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
2
Question by qwert024 · Jan 19, 2016 at 08:02 AM · meshesprocedural meshefficiencymesh verticesmesh-deformation

Dynamically move vertices of a mesh

Hello! I just start learning to make procedural mesh from code. I made a procedural mesh ( just a simple triangle ) and want to randomly change the vertices' position when pressing a key. Here is my code:

 using UnityEngine;
 using System.Collections;
 
 public class MyMesh : MonoBehaviour {
 
     public Vector3 p1 = new Vector3(-1,0,0);
     public Vector3 p2 = new Vector3(0,2,0);
     public Vector3 p3 = new Vector3(1,0,0);
 
     void Start () {
         MeshFilter mf = GetComponent<MeshFilter>();
         Mesh mesh = new Mesh();
         mesh = mf.mesh;
 
         Vector3[] vertices = new Vector3[]
         {
             p1,
             p2,
             p3
         };
 
         int[] triangles = new int[]
         {
             0,1,2
         };
 
         Vector3[] normals = new Vector3[]
         {
             Vector3.forward,
             Vector3.forward,
             Vector3.forward
         };
 
         mesh.vertices = vertices;
         mesh.triangles = triangles;
         mesh.normals = normals;
     }
     
     void Update () {
         if(Input.GetKeyDown("up")){
             p1 = Random.insideUnitSphere;
             p2 = Random.insideUnitSphere;
             p3 = Random.insideUnitSphere;
             Debug.Log("Up is pressed.");
         }
     }
 }
 

When I hit play, the mesh showed up correctly. And then I pressed the up button, I saw the console show "Up is pressed." and the position of p1, p2, p3 change in the inspector. But the mesh in the game view looks the same, didn't change its shape. Where did I get wrong?

Also tried putting all of the code into Update().

 using UnityEngine;
 using System.Collections;
 
 public class MyMesh1 : MonoBehaviour {
 
     public Vector3 p1 = new Vector3(-1,0,0);
     public Vector3 p2 = new Vector3(0,2,0);
     public Vector3 p3 = new Vector3(1,0,0);
 
     void Update () {
         MeshFilter mf = GetComponent<MeshFilter>();
         Mesh mesh = new Mesh();
         mesh = mf.mesh;
 
         Vector3[] vertices = new Vector3[]
         {
             p1,
             p2,
             p3
         };
 
         int[] triangles = new int[]
         {
             0,1,2
         };
 
         Vector3[] normals = new Vector3[]
         {
             Vector3.forward,
             Vector3.forward,
             Vector3.forward
         };
 
         mesh.vertices = vertices;
         mesh.triangles = triangles;
         mesh.normals = normals;
     
         if(Input.GetKeyDown("up")){
             p1 = Random.insideUnitSphere;
             p2 = Random.insideUnitSphere;
             p3 = Random.insideUnitSphere;
             Debug.Log("Up is pressed.");
         }
     }
 }
 

It works just like what I want: Every time I press the up button, the mesh's vertices change their position so the mesh changes its shape randomly. However, Update() is called every frame so I am worried that it's really bad to put GetComponent, new Vector3 array etc. in Update()! Are there any other good ways to dynamically deform a mesh? Thank you!!

Comment
Add comment · Show 1
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 cjdev · Jan 19, 2016 at 11:16 PM 1
Share

You can use $$anonymous$$esh.$$anonymous$$arkDynamic to move around a lot of vertices every frame with a mesh. You can do it for quite a lot of vertices before you get a significant performance impact.

2 Replies

· Add your reply
  • Sort: 
avatar image
5
Best Answer

Answer by NoseKills · Jan 19, 2016 at 06:49 PM

There are a few issues in your approach. Firstly, totally unrelated to meshes: When you do something like this (essentially what you are doing now)

 public Vector3 p1 = new Vector3(-1,0,0);
 Vector3[] vertices = new Vector3[] { p1 };
 p1 = new Vector3(2,2,2);

This doesn't change the contents of the array for 2 reasons (sort of). First reason is that Vector3 is a struct, not a class, so its passed as a value, not as reference (more on that later).

The other reason this doesn't work is (lets pretend Vector3 is a ref type): You declare p1 - a reference to a memory address that holds vector (-1,0,0). You put a reference to that address into your array. All fine so far. The last line doesn't change the data that is stored in your memory address; it assigns p1 to point to a different memory address that holds another vector (2,2,2). Your array still holds a reference to the old address with (-1,0,0).

So in theory this should work better:

 Vector3 p1 = new Vector3(-1, 0, 0);
 Vector3[] vertices = new Vector3[] { p1 };
 p1.x = 2;
 p1.y = 2;
 p1.z = 2;
 Debug.Log(vertices[0]);

Now we are changing the data inside the object the memory address points to - p1 and vecrtices[0] reference the same address so it should work? If you try that, it doesn't, which is due to the second issue that Vector3 isn't a reference type.

Because of that, when you put p1 into the array, the array doesn't get a reference to the original vector but rather gets a copy of the vector that just has the same value(s).

That was basic programming, and a big reason to why the mesh isn't changing: You aren't actually changing the vertices because changing p1, p2 and p3 don't change the contents of the mesh.vertices array.

A third issue is that even is you could change the contents of the mesh.vertices array by changing individual Vectors in it, Unity needs to know the changes so it can pass the new values to the rendering pipeline and eventually make the change visible on your screen.

That's why, if you want the mesh to change, you need to assign a new array into 'mesh.vertices'. It's not an array variable but a property that not only takes in the new array, but also takes the necessary steps to make the changes visible on screen.

The same applies to all the other properties like mesh.normals etc.

So finally, you should do it something like:

     Vector3[] vertices = new Vector3[]
     {
             new Vector3(-1, 0, 0),
             new Vector3(0, 2, 0),
             new Vector3(1, 0, 0)
     };
     int[] triangles = new int[]
     {
             0,1,2
     };
     Vector3[] normals = new Vector3[]
     {
             Vector3.forward,
             Vector3.forward,
             Vector3.forward
     };
 
     private MeshFilter mf;
 
     void Start() {
         mf = GetComponent<MeshFilter>();
         mf.mesh = new Mesh();
         mf.mesh.vertices = vertices;
         mf.mesh.triangles = triangles;
         mf.mesh.normals = normals;
     }
 
     void Update() {
         if (Input.GetKeyDown("up")) {
             mf.mesh.vertices = new[]
             {
                     Random.insideUnitSphere,
                     Random.insideUnitSphere,
                     Random.insideUnitSphere
             };
             Debug.Log("Up is pressed.");
         }
     }

Comment
Add comment · Show 4 · 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 qwert024 · Jan 20, 2016 at 04:27 PM 1
Share

Thank you! Learned a lot about the value type and reference type! I am new to code and have to work harder. Now I am thinking if I want to play a song, and use the loudness to change the meshes like this: https://vimeo.com/groups/308518/videos/79533030 Does that mean I have to keep assigning new arrays into 'mesh.vertices'?

avatar image NoseKills qwert024 · Jan 20, 2016 at 09:03 PM 2
Share

Does that mean I have to keep assigning new arrays into 'mesh.vertices'?

We have to be very careful with word choices here :) Yes, you have to assign an array to mesh.vertices in order to see any changes on screen, so the only way to save performance is not to make "new arrays". You should make one array like in the example, put new Vectors into it or change them, and then assign this array with changed contents into mesh.vertices every time.

For example

         Vector3[] verts = new Vector3[] {
         new Vector3(1, 1, 1),
         new Vector3(2, 2, 2)
     };
     void Start () {
         verts[0].x = 4;
         verts[0].y++;
         verts[0].z *= 10;
         verts[1] = new Vector3(3, 3, 3);
         Debug.Log(verts[0] + " - " + verts[1]);
            mesh.vertices = verts;
     }

It's definitely not a big deal especially in a program like this, but using the "new" keyword means you are creating something new into memory. And everything "new" will most likely have to be garbage collected eventually when you are done using it (can be slow).

That being said, don't be afraid of the "new" keyword. You have to use it all the time. But this is just an obvious case where you can create just one array and keep re-using it ins$$anonymous$$d of making new ones.

avatar image cjdev NoseKills · Jan 20, 2016 at 09:21 PM 0
Share

Some good points, but while creating new objects (classes) certainly can and will trigger garbage collection, value types are created on the stack and their memory deallocation isn't handled by garbage collection.

Show more comments
avatar image
0

Answer by mikelortega · Jan 19, 2016 at 08:09 AM

I would create a new function, for instance UpdateTriangleMesh(), and put your code there.

Then, call this function in Start.

 void Start()
 {
     UpdateTriangleMesh();
 }

And call this function every time you press "up", inside the if, this way it will be called only when you press that key.

 void Update()
 {
     if (Input.GetKeyDown("up"))
         UpdateTriangleMesh();
 }
Comment
Add comment · Show 1 · 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 qwert024 · Jan 20, 2016 at 04:33 PM 1
Share

Thanks! It's a clearer way!

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

7 People are following this question.

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

Related Questions

How to fill out a procedurally generated mesh with quads of varying sizes? 0 Answers

Accessing mesh vertices is extremely inefficient; any workarounds? 0 Answers

Sort a list based on edge connections 1 Answer

make one mesh follow the deformations of the other,adjust mesh to follow deformations of another(cloth, hair) 0 Answers

Creating a convex MESH (not collider) 2 Answers


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