6
\$\begingroup\$

Does Unity allow streaming mesh data that can be continuously changed?

I have a level that is dynamically changing based on some parameters. The number of triangles stays the same, they just change positions.

I'm speaking of around 2000 triangles that need their position updated each frame (they follow a spline that is computed on CPU), running on mobile phones.

I can't use a TrailRenderer because the object is a whole level. I can't use bones, because I need to know the final position for each vertex for my custom collision code.

The mesh should be marked Mesh.MarkDynamic.

\$\endgroup\$
7
\$\begingroup\$

Yes, you can change a mesh at runtime.

  1. get the current mesh from your object using Mesh mesh = GetComponent<MeshFilter>().mesh. Alternatively, if you want to replace the mesh with a completely new one, create one with Mesh mesh = new Mesh(); and assign it to your object with GetComponent<MeshFilter>().mesh = mesh;
  2. When you intend to modify the same mesh every frame, you should call the MarkDynamic() method on it. This might improve performance in that situation (thanks, Kroltan).
  3. Modify the Mesh object. It is a reference-type, so any changes you make will be reflected by the object which owns the mesh. For a minimum functional mesh you need to set at least its .vertices and .triangles component, if you want it to be textured also the uv component. If you are really just going to change the positions of vertices of an existing mesh, then the .vertices property is likely the only one you need. But keep in mind that you have little control over the order in which your 3d modeling program saves the vertices of a 3d model, so a slight change to the model can mean that the indexes of all vertices change in a completely unpredictable way.
  4. When you are finished, call mesh.RecalculateNormals which is required by almost every shader to calculate brightness levels correctly.
  5. The .tangents component is also important for some shaders, especially those which use bump mapping. The documentation warns that it needs to be set after you updated the normals.
  6. If you use that mesh for a MeshCollider, you should also call mesh.RecalculateBounds. You mentioned you are doing collision detection all by yourself, so this might not be necessary in your case, but it might be necessary for other people.

Unity also made an example of procedural mesh generation as a complete project on the asset store available for free.

Will it be fast enough for mobile phones? That depends on countless factors, like what kind of mobile phone you are talking about, how often you are going to change the mesh, how effective your mesh changing algorithm is, what shaders you are using and much more. You need to test it for yourself. By the way, if your changes will usually be localized, it might help to break down your terrain into multiple sub-objects and only update the meshes of those which were affected.

\$\endgroup\$
  • 1
    \$\begingroup\$ ah the most important point I think since I change it every frame. Thanks! \$\endgroup\$ – GameDeveloper Jan 23 '17 at 9:28
3
\$\begingroup\$

As Philipp said, you can change the mesh at runtime. You might have performance issues though (it's not "streaming" at all); in particular RecalculateNormals will probably be quite long.

If you're willing to accept the maintenance burden, another possibility is to compute the vertices position directly in the vertex shader. Since you have custom collision code, you'll have to compute 2 versions : one on the CPU, one on the GPU.

If you plan to use a MeshCollider, this idea is useless (it needs a Mesh anyway).

EDIT : I completely forgot about Mesh.MarkDynamic. This is definitely the way to go. I'll leave my answer just in case, though.

\$\endgroup\$
  • \$\begingroup\$ You could improve your answer by providing a simple example of a custom vertex shader in Unity. \$\endgroup\$ – Philipp Jan 22 '17 at 16:26
  • \$\begingroup\$ It's all in the docs : docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html You just have to compute o.pos yourself. \$\endgroup\$ – Calvin1602 Jan 22 '17 at 17:06
  • \$\begingroup\$ it is not possible mesh "streaming" correct? for the normals I'll use some tricks to speed up since a /sqrt(magnitude) can be pretty expensive. Then mesh is changed everyframe by the way. \$\endgroup\$ – GameDeveloper Jan 23 '17 at 9:27
  • \$\begingroup\$ See my edit. Regarding sqrt() : you'll have to do it every frame anyway, so I'd rather do it on the GPU. \$\endgroup\$ – Calvin1602 Jan 23 '17 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.