Search Unity

Advantages of sharing mesh between MeshFilters other than memory size

Discussion in 'Scripting' started by Efril, Aug 14, 2019.

  1. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    Hello all. I'm working on game graphics optimization and I faced a small question. Imagine a warship which have few guns on board. Each gun is a game object with MeshFilter which have unique sharedMesh. These meshes are absolutely idential and material they use is the same. These meshes are just copied in 3d application. This logical structure is shown on the scheme below:
    CurrentStructure.png
    Evidient optimization here is using the same mesh for all game objects and ajusting their positions and rotations. So logical structure will look like this:
    PossibleOptimizationStructure.png
    Important note: guns belongs to the same ship and that is why will often be visible at the same time.
    Question: will this optimization give any advantages except memory usage reduction?
    Thanks in advance.
     
  2. Grizmu

    Grizmu

    Joined:
    Aug 27, 2013
    Posts:
    131
    It will give improvement, even if you are not using static batching.

    Testing with 10000 instances of a basic cube, they use about 17.5ms CPU time per frame to render using a shared mesh, while having them all use an unique mesh uses about 25.81ms of the CPU time per frame, what is a 47.4% difference.
    SharedMesh.png
    UniqueMesh.png
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MeshTest : MonoBehaviour{
    4.     public int objectsToSpawn = 10000;
    5.     public bool sharedMesh = false;
    6.     public bool sharedMaterial = false;
    7.     public float range = 10.0f;
    8.  
    9.     Mesh mesh;
    10.     Material mat;
    11.  
    12.     private void Awake() {
    13.         Init();
    14.         SpawnGOs();
    15.     }
    16.  
    17.     void Init() {
    18.         var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
    19.         var mf = go.GetComponent<MeshFilter>();
    20.         var mr = go.GetComponent<MeshRenderer>();
    21.  
    22.         mesh = mf.sharedMesh;
    23.         mat = mr.sharedMaterial;
    24.         Destroy(go);
    25.     }
    26.  
    27.     public void SpawnGO(int id, Vector3 pos) {
    28.         var go = new GameObject($"GO {id}");
    29.        
    30.         var transf = go.GetComponent<Transform>();
    31.         var mf = go.AddComponent<MeshFilter>();
    32.         var mr = go.AddComponent<MeshRenderer>();
    33.  
    34.         transf.position = pos;
    35.  
    36.         if(sharedMesh) mf.sharedMesh = mesh;
    37.         else mf.mesh = Instantiate(mesh);
    38.  
    39.         if(sharedMaterial) mr.sharedMaterial = mat;
    40.         else mr.material = Instantiate(mat);
    41.     }
    42.  
    43.     public void SpawnGOs() {
    44.         for(int i =0 ; i < objectsToSpawn; i++) {
    45.             SpawnGO(i, Random.insideUnitSphere * range);
    46.         }
    47.     }
    48. }
     
    Deleted User and Efril like this.
  3. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    Thank you, @Griz , for the clear answer.
     
    Grizmu likes this.