51517860
Many times we need to combine material balls with the same shader to reduce the drawcall.
For example, in the Kowloon War, a character with 10 parts, 10 parts of each from different FBX files, plus the body, there are 11 of material balls, accounting for 11 drawcall. If there are 10 characters running in the main city, the light figure takes up 110 drawcall! So the material ball merging is necessary at this time.
(Multi-part facelift effect in Kowloon War)
Material ball Merge, divided the following steps to go, first we discuss the common meshrenderer material ball merge, and then discuss the skinnedmeshrenderer of the material ball merge.
Common meshrenderer material balls are combined:
1. Combine all the textures that the ball is carrying, create a new material ball, and assign the merged map to the new material ball.
2. Record the rect of each merged map in the new map, and save it with a rect[] array.
3. Merge the meshes and brush the Uvs of each mesh that need to be merged, according to the rect[of the 2nd step].
4. Give the new material ball to the merged mesh, and only 1 drawcall.
Here is the key code:
- void Combinemesh ()
- {
- meshfilter[] Mfchildren = getcomponentsinchildren<meshfilter> ();
- Combineinstance[] Combine = new combineinstance[mfchildren.length];
- meshrenderer[] Mrchildren = getcomponentsinchildren<meshrenderer> ();
- material[] Materials = new material[mrchildren.length];
- Meshrenderer mrself = gameobject.addcomponent<meshrenderer> ();
- Meshfilter mfself = gameobject.addcomponent<meshfilter> ();
- texture2d[] Textures = new texture2d[mrchildren.length];
- For (int i = 0; i < mrchildren.length; i++)
- {
- if (Mrchildren[i].transform = = transform)
- {
- continue;
- }
- Materials[i] = mrchildren[i].sharedmaterial;
- Texture2d tx = Materials[i]. GetTexture ("_maintex") as texture2d;
- Texture2d tx2d = new Texture2d (Tx.width, Tx.height, Textureformat.argb32, false);
- Tx2d.setpixels (TX. Getpixels (0, 0, Tx.width, tx.height));
- Tx2d.apply ();
- Textures[i] = tx2d;
- }
- Material materialnew = new Material (materials[0].shader);
- Materialnew.copypropertiesfrommaterial (materials[0]);
- Mrself.sharedmaterial = materialnew;
- Texture2d texture = new Texture2d (1024x768, 1024x768);
- Materialnew.settexture ("_maintex", texture);
- rect[] rects = texture. Packtextures (Textures, ten, 1024x768);
- For (int i = 0; i < mfchildren.length; i++)
- {
- if (Mfchildren[i].transform = = transform)
- {
- continue;
- }
- Rect rect = rects[i];
- Mesh meshcombine = Mfchildren[i].mesh;
- vector2[] Uvs = new Vector2[meshcombine.uv.length];
- //The UV of the grid is brushed over the map's rect
- For (int j = 0; j < Uvs. Length; J + +)
- {
- uvs[j].x = rect.x + meshcombine.uv[j].x * rect.width;
- UVS[J].Y = Rect.y + meshcombine.uv[j].y * rect.height;
- }
- MESHCOMBINE.UV = Uvs;
- Combine[i].mesh = Meshcombine;
- Combine[i].transform = Mfchildren[i].transform.localtoworldmatrix;
- Mfchildren[i].gameobject.setactive (false);
- }
- Mesh Newmesh = new Mesh ();
- Newmesh.combinemeshes (Combine, true,true); Merging grids
- Mfself.mesh = Newmesh;
- }
Pre-merger Drawcall:
Drawcall after merging:
Merged grid:
Merge the good stickers:
Below we will discuss the merger of Skinnedmeshrenderer.
Skinnedmeshrenderer is a little bit more troublesome than meshrenderer because skinnedmeshrenderer to deal with bones.
Here are the steps:
1. Combine all the textures that the ball is carrying, create a new material ball, and assign the merged map to the new material ball.
2. Record the rect of each merged map in the new map, and save it with a rect[] array.
3. Record the bones of the skinnedmeshrenderer that need to be merged.
4. Merge the meshes and brush the Uvs of each mesh that need to be merged, according to the rect[of the 2nd step].
5. Assign the merged grid to the new Skinnedmeshrenderer and give the new Skinnedmeshrenderer the bones recorded in the 3rd step.
6. Give the new material ball to the merged mesh, and only 1 drawcall.
The steps in the red section above are different from the meshrenderer.
Here is the key code:
- void Combinemesh ()
- {
- skinnedmeshrenderer[] SMRs = getcomponentsinchildren<skinnedmeshrenderer> ();
- Combineinstance[] Combine = new Combineinstance[smrs. Length];
- material[] Materials = new Material[smrs. Length];
- texture2d[] Textures = new Texture2d[smrs. Length];
- Skinnedmeshrenderer smrcombine = combinemesh.gameobject.addcomponent<skinnedmeshrenderer> ();
- Smrcombine.shadowcastingmode = UNITYENGINE.RENDERING.SHADOWCASTINGMODE.OFF;
- Smrcombine.receiveshadows = false;
- For (int i = 0; i < SMRs. Length; i++)
- {
- Materials[i] = smrs[i].sharedmaterial;
- Texture2d tx = Materials[i]. GetTexture ("_maintex") as texture2d;
- Texture2d tx2d = new Texture2d (Tx.width, Tx.height, Textureformat.argb32, false);
- Tx2d.setpixels (TX. Getpixels (0, 0, Tx.width, tx.height));
- Tx2d.apply ();
- Textures[i] = tx2d;
- }
- Material materialnew = new Material (materials[0].shader);
- Materialnew.copypropertiesfrommaterial (materials[0]);
- Texture2d texture = new Texture2d (1024x768, 1024x768);
- rect[] rects = texture. Packtextures (Textures, ten, 1024x768);
- Materialnew.settexture ("_maintex", texture);
- list<transform> bonetmp = new list<transform> ();
- For (int i = 0; i < SMRs. Length; i++)
- {
- if (Smrs[i].transform = = transform)
- {
- continue;
- }
- Rect rect = rects[i];
- Mesh meshcombine = Creatmeshwithmesh (Smrs[i].sharedmesh);
- vector2[] Uvs = new Vector2[meshcombine.uv.length];
- For (int j = 0; j < Uvs. Length; J + +)
- {
- uvs[j].x = rect.x + meshcombine.uv[j].x * rect.width;
- UVS[J].Y = Rect.y + meshcombine.uv[j].y * rect.height;
- }
- Bonetmp.addrange (Smrs[i].bones);
- MESHCOMBINE.UV = Uvs;
- Combine[i].mesh = Meshcombine;
- Combine[i].transform = Smrs[i].transform.localtoworldmatrix;
- Gameobject.destroy (Smrs[i].gameobject);
- }
- Mesh Newmesh = new Mesh ();
- Newmesh.combinemeshes (Combine, true, true);
- Smrcombine.bones = Bonetmp.toarray ();
- Smrcombine.rootbone = Rootbone;
- Smrcombine.sharedmesh = Newmesh;
- Smrcombine.sharedmaterial = materialnew;
- }
- mesh creatmeshwithmesh (mesh mesh)
- {
- Mesh mtmp = new Mesh ();
- Mtmp.vertices = mesh.vertices;
- Mtmp.name = Mesh.name;
- MTMP.UV = MESH.UV;
- Mtmp.uv2 = Mesh.uv2;
- Mtmp.uv2 = Mesh.uv2;
- mtmp.bindposes = mesh.bindposes;
- Mtmp.boneweights = mesh.boneweights;
- Mtmp.bounds = Mesh.bounds;
- Mtmp.colors = mesh.colors;
- Mtmp.colors32 = MESH.COLORS32;
- Mtmp.normals = mesh.normals;
- Mtmp.submeshcount = Mesh.submeshcount;
- Mtmp.tangents = mesh.tangents;
- Mtmp.triangles = Mesh.triangles;
- return mtmp;
- }
Before merging, there are two meshes, which occupy 2drawcall, respectively, the mesh and material balls of the characters and knives.
After merging, it takes only 1 drawcall, and Animationcontroller and its animations work:
Merged grid:
Merge the good stickers:
The above is the merger of mesh and material content, currently only focus on implementation, but also can be further optimized, there are the following points to note:
1. The combined material ball needs to use the same shader, if more than one material ball uses the different shader, must do the further classification processing.
2. The Read/write enable option of the texture file used for the material ball is ticked.
Project's GitHub address: Https://github.com/arBao/MeshMaterialCombine
Original articles, reproduced please specify the source: http://blog.csdn.net/dardgen2015/article/details/51517860
Grids in Unity merge with material balls