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
1
Question by starstriker1 · Oct 29, 2012 at 04:42 AM · meshperformanceoptimizationskinningpose

Performance issues with mesh processing

In order to create a certain effect, I need to calculate the pose of a set of skinned meshes, since Unity doesn't expose that data in version 3. I was able to get everything working, but I'm suffering from some major performance issues. Since I don't have Unity Pro, I did some ad-hoc timing of functions using Time.realtimeSinceStart and narrowed down my bottleneck to this section of code:

 private function CalculatedPosedMesh(skinnedMesh : SkinnedMeshRenderer) : Mesh
 {
     // Build a new mesh
     var baseMesh = skinnedMesh.sharedMesh;
     var mesh = new Mesh();
 
     var baseMeshVertices = baseMesh.vertices;
     var baseMeshVerticesLength = baseMeshVertices.Length;
     var baseMeshBoneWeights = baseMesh.boneWeights;
     var baseMeshBindPoses = baseMesh.bindposes;
     var newVert : Vector3[] = new Vector3[baseMeshVertices.Length];
     
     var i : int = 0;
     for(i = 0; i < baseMeshVerticesLength; i++)
     {
         //Only the first bone is being factored in right now in order to cut down on calculations. 

         // Apply bone weights
         newVert[i] = GetBoneInfluence(skinnedMesh, baseMesh, baseMeshBoneWeights[i].boneIndex0, 1.0, baseMeshVertices[i]);
             
         // Transform the vertex to be in local space for convenience.
         newVert[i] -= transform.position;
     }
     
     mesh.vertices = newVert;
     mesh.uv = baseMesh.uv;
     mesh.triangles = baseMesh.triangles;
     
     mesh.RecalculateBounds();
     mesh.RecalculateNormals();
     
     return mesh;
 }
 
 private function GetBoneInfluence(skinnedMesh : SkinnedMeshRenderer, baseMesh : Mesh, boneIndex : int, boneWeight : float, vertex : Vector3) : Vector3
 {
     // Transform the mesh vertice first so that it's local in bone space, and then transform the
     // local coordinates to world coordinates using the current bone transform.
     var localVertexPosition : Vector3 = baseMesh.bindposes[boneIndex].MultiplyPoint3x4( vertex );
         
     return skinnedMesh.bones[boneIndex].transform.localToWorldMatrix.MultiplyPoint3x4( localVertexPosition ) * boneWeight;
 }

This code works just fine, and the effect looks excellent, but this piece of code is causing 0.2-1.0 second hitches each time I call it on a 3k vertex mesh, which is not acceptable. I was able to optimize it down to what it is now by caching a lot of the return values from the mesh class (a lot of functionality is apparently being done behind the scenes by the property accessors), but I've run out of ideas in that regard. If I can bring the calculation cost down consistently to half a second or less, I think I can mask the rest of it with multithreading or coroutines.

Can anyone spot redundant or unnecessary operations here that I might have missed, or another way to approach the problem? Any help would be appreciated!

Comment
Add comment
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

1 Reply

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

Answer by Paulius-Liekis · Oct 29, 2012 at 09:35 AM

As it was said in the comments: runtime mesh modification is an expensive operation.

But besides that move these out of the loop:

 baseMesh.bindposes[boneIndex]
 skinnedMesh.bones[boneIndex]

Don't ever dobaseMesh.bindposes[index] or mesh.vertices[index], etc in the loop. Every time this operations is performed Unity does a copy of C++ data into C# (whole array! and in vertices case it has to convert data from combined vertex stream to Vector3 array). Simply do this before the loop:

 Matrix4x4[] bindposes = baseMesh.bindposes[boneIndex];

this way a copy of the array is performed only once - not on every vertex. And then use bindposes[index] in the loop.

IIRC Unity caches result of localToWorldMatrix, but simply creating an array of matrices before the main loop and caching them should help a bit too.

Comment
Add comment · Show 5 · 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 starstriker1 · Oct 30, 2012 at 03:55 AM 0
Share

I was able to track down the main point of slowdown: the "mesh.vertices = newVert;" line. The vertex calculations themselves were actually trivial, since I was already caching the problem variables. Fortunately, all I really needed were the vertex positions for my effect, so cutting out that line and just storing the array of vertices ins$$anonymous$$d of a mesh got this whole thing into real-time territory.

Thanks for the insights, guys, I hadn't realized just how much functionality was being hidden behind the accessors.

avatar image daterre · Nov 01, 2012 at 06:58 AM 0
Share

There should be some documentation or wiki page which lists these horrendous accessor operations. I've been doing similar real-time deformations myself and little bits of info like "Every time this operations is performed Unity does a copy of C++ data into C#" can save days and weeks of debugging!

avatar image Paulius-Liekis · Nov 01, 2012 at 09:26 AM 0
Share

@daterre, well...this actually applies to almost any array that you get from Unity API in C# - almost all of them perform a data copy from C++ to C# (and vice versa). $$anonymous$$aybe vertices (normals, tangents and other mesh data) is more extreme, because Unity not only converts data, but also (un)packs into streams.

avatar image daterre · Nov 01, 2012 at 11:07 AM 0
Share

That makes sense...even though I'd expect some kind of property value caching for the duration of an update. Is it theoretically possible to write a C++ plugin in Pro that performs mesh queries/operations and only exposes to script scenario-specific values? Or does the plugin run in a sandbox and marshaling occurs anyway?

avatar image Paulius-Liekis · Nov 01, 2012 at 12:54 PM 0
Share

No, I don't think you can access Unity C++ data from your C++ plugin. You would still have to get data in your C# script and pass that to your C++ plugin, so it wouldn't help at all. The only time where is makes sense is when you're doing a lot of mesh processing.

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

11 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

Related Questions

Optimize mesh for runtime performance 0 Answers

Combining meshes doesn't reduce triangle count 0 Answers

What's the best way to optimise thousands of instances of the same mesh? 2 Answers

Substract mesh from Skinned Mesh Renderer 0 Answers

Size of a mesh vs performance 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