Search Unity

GenerateSecondaryUVSet destroying mesh

Discussion in 'Editor & General Support' started by Glockenbeat, Nov 22, 2012.

  1. Glockenbeat

    Glockenbeat

    Joined:
    Apr 24, 2012
    Posts:
    670
    Hey there,

    I have built an editor class which basically derives from the MeshMerger script from the Wiki:
    http://wiki.unity3d.com/index.php?title=MeshMerger

    I've extended this script and changed it so that

    1.) it's working in the editor rather than in ingame to be able to generate lightmaps for the geometry as well
    2.) it keeps track of vertex colors and copies them over as well
    and finally
    3.) is supposed to generate a UV2 set for lightmapping using Unwrapping.GenerateSecondaryUVSet()

    So here's the important part of the script:

    Code (csharp):
    1.  
    2.         Mesh me = new Mesh();      
    3.         me.name = gameObject.name;
    4.         me.vertices = verts;
    5.         me.normals = norms;
    6.         me.boneWeights = weights;
    7.         me.bindposes = bindPoses;
    8.         me.uv = uvs;
    9.         me.triangles = tris;
    10.         me.colors32 = vertColors;
    11.        
    12.         if (generateLightmapUVs) {
    13.             Unwrapping.GenerateSecondaryUVSet(me);
    14.         }
    15.  
    Problem is however that this actually destroys the mesh. Please have a look at the before/after screenshot attached.

    If I leave the generate UVs step aside (generateLightmapUVs = false), everything looks good as expected.

    Did anyone of you encounter this and possibly know of a fix?

    Cheers,
    Beat

    Btw. still on 3.5.6f4

    edit: Just noticed would be better suited for the scripting boards. Whops.
     

    Attached Files:

    Last edited: Nov 23, 2012
  2. Glockenbeat

    Glockenbeat

    Joined:
    Apr 24, 2012
    Posts:
    670
    Answering to my own thread here.

    It seems like the MeshMerger script from the wiki itself was causing this trouble. On fourth thought and investigation it seems like copying of triangles and vertices is kind of buggy in the script, so finally I also saw some lonesome vertices flowing in the world after combining. Therefore it might not be the best idea to use that script at all.

    Nevertheless, the CombineChildren script from the Standard Assets turned out to be a much better basis to work with. I've rewritten parts of it now to suit my needs, which basically is generating the combined static geometry in the editor and being able to generate lightmaps for this as well. Works like a charm!

    I've seen this topic multiple times in the community without a real solution, so it might be a good idea to have a script ready for this. No big adjustment, but I hope it helps some people out there. Here it is, use it as you wish.

    CombineChildrenAdvanced.cs
    Usage: Place this anywhere in your project and attach it to the parent gameObject containing the other meshes to be combined.
    Basically it delivers the very same feature as the standard CombineChildren script, yet it needs to be executed in the editor.
    By default it'll automatically generate the lightmapping UVs for the combined geometry. If you don't want this to happen, either use the CombineChildren.cs from the Standard Assets, or uncheck the corresponding checkbox.
    If you want to split geometry up again, just use the corresponding button. It'll reset everything accordingly.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. /*
    5. Attach this script as a parent to some game objects. Then by using the corresponding controls you may generate combined meshes (with lightmapping UVs).
    6. This is useful as a performance optimization since it is faster to render one big mesh than many small meshes. See the docs on graphics performance optimization for more info.
    7.  
    8. Different materials will cause multiple meshes to be created, thus it is useful to share as many textures/material as you can.
    9. NOTE: Using multiple materials may break things due to lightmapping generation. So lightmapping UVs as well as splitting the combined geometry is not supported.
    10. Workaround: Create hierarchies in which the children only have exactly one material.
    11. */
    12.  
    13. [AddComponentMenu("Mad Vulture Games/Combine Children 1.5")]
    14. public class CombineChildrenAdvanced : MonoBehaviour {
    15.    
    16.     /// Usually rendering with triangle strips is faster.
    17.     /// However when combining objects with very low triangle counts, it can be faster to use triangles.
    18.     /// Best is to try out which value is faster in practice.
    19.     public bool generateTriangleStrips = true;
    20.     public bool generateLightmappingUVs = true;
    21.     public bool isCombined = false;
    22.    
    23.     public void Combine() {
    24.         Component[] filters  = GetComponentsInChildren(typeof(MeshFilter));
    25.        
    26.         if (filters.Length <= 1) {
    27.             Debug.LogWarning ("Not enough meshes to combine!");
    28.             return;
    29.         }
    30.        
    31.         Matrix4x4 myTransform = transform.worldToLocalMatrix;
    32.         Hashtable materialToMesh= new Hashtable();
    33.        
    34.         for (int i=0;i<filters.Length;i++) {
    35.             MeshFilter filter = (MeshFilter)filters[i];
    36.             Renderer curRenderer  = filters[i].renderer;
    37.             MeshCombineUtility.MeshInstance instance = new MeshCombineUtility.MeshInstance ();
    38.             instance.mesh = filter.sharedMesh;
    39.             if (curRenderer != null  curRenderer.enabled  instance.mesh != null) {
    40.                 instance.transform = myTransform * filter.transform.localToWorldMatrix;
    41.                
    42.                 Material[] materials = curRenderer.sharedMaterials;
    43.                 for (int m=0;m<materials.Length;m++) {
    44.                     instance.subMeshIndex = System.Math.Min(m, instance.mesh.subMeshCount - 1);
    45.    
    46.                     ArrayList objects = (ArrayList)materialToMesh[materials[m]];
    47.                     if (objects != null) {
    48.                         objects.Add(instance);
    49.                     }
    50.                     else
    51.                     {
    52.                         objects = new ArrayList ();
    53.                         objects.Add(instance);
    54.                         materialToMesh.Add(materials[m], objects);
    55.                     }
    56.                 }
    57.                
    58.                 curRenderer.enabled = false;
    59.             }
    60.         }
    61.    
    62.         foreach (DictionaryEntry de  in materialToMesh) {
    63.             ArrayList elements = (ArrayList)de.Value;
    64.             MeshCombineUtility.MeshInstance[] instances = (MeshCombineUtility.MeshInstance[])elements.ToArray(typeof(MeshCombineUtility.MeshInstance));
    65.  
    66.             // We have a maximum of one material, so just attach the mesh to our own game object
    67.             if (materialToMesh.Count == 1)
    68.             {
    69.                 // Make sure we have a mesh filter  renderer
    70.                 if (GetComponent(typeof(MeshFilter)) == null)
    71.                     gameObject.AddComponent(typeof(MeshFilter));
    72.                 if (!GetComponent("MeshRenderer"))
    73.                     gameObject.AddComponent("MeshRenderer");
    74.    
    75.                 MeshFilter filter = (MeshFilter)GetComponent(typeof(MeshFilter));
    76.                 filter.mesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
    77.                 renderer.material = (Material)de.Key;
    78.                 renderer.enabled = true;
    79.             }
    80.             // We have multiple materials to take care of, build one mesh / gameobject for each material
    81.             // and parent it to this object
    82.             else
    83.             {
    84.                 GameObject go = new GameObject("Combined mesh");
    85.                 go.transform.parent = transform;
    86.                 go.transform.localScale = Vector3.one;
    87.                 go.transform.localRotation = Quaternion.identity;
    88.                 go.transform.localPosition = Vector3.zero;
    89.                 go.AddComponent(typeof(MeshFilter));
    90.                 go.AddComponent("MeshRenderer");
    91.                 go.renderer.material = (Material)de.Key;
    92.                 MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter));
    93.                 filter.mesh = MeshCombineUtility.Combine(instances, generateTriangleStrips);
    94.             }
    95.         }
    96.        
    97.         isCombined = true;
    98.     }
    99. }
    100.  





    CombineChildrenAdvancedEditor.cs
    Usage: Place this in your Assets/Editor folder, it actually contains the main part of it.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.Collections;
    5.  
    6. [CustomEditor(typeof(CombineChildrenAdvanced))]
    7. public class CombineChildrenAdvancedEditor : Editor {
    8.  
    9.     CombineChildrenAdvanced _target;
    10.    
    11.     void OnEnable() {
    12.         _target = (CombineChildrenAdvanced)target;
    13.     }
    14.    
    15.    
    16.    
    17.     public override void OnInspectorGUI() {
    18.        
    19.         EditorGUIUtility.LookLikeInspector();
    20.        
    21.         _target.generateTriangleStrips = EditorGUILayout.Toggle("Generate Triangle Strips", _target.generateTriangleStrips);
    22.         _target.generateLightmappingUVs = EditorGUILayout.Toggle ("Generate Lightmapping UVs", _target.generateLightmappingUVs);
    23.        
    24.         if (!_target.isCombined) {
    25.             if (GUILayout.Button ("Combine now (May take a while!)")) {
    26.                 _target.Combine();
    27.                
    28.                 if (_target.generateLightmappingUVs) {
    29.                     GenerateLightmappingUVs();
    30.                 }
    31.             }
    32.         }
    33.        
    34.         if (_target.isCombined) {
    35.             if (GUILayout.Button ("Generate Lightmap UVs")) {
    36.                 GenerateLightmappingUVs();
    37.             }
    38.            
    39.             if (GUILayout.Button ("Split Mesh")) {
    40.                 DestroyImmediate(_target.GetComponent (typeof(MeshFilter)));
    41.                 DestroyImmediate(_target.GetComponent (typeof(MeshRenderer)));
    42.                
    43.                 foreach (MeshRenderer mr in _target.GetComponentsInChildren(typeof(MeshRenderer))) {
    44.                     mr.enabled = true;
    45.                 }
    46.                
    47.                 _target.isCombined = false;
    48.             }
    49.         }
    50.     }
    51.    
    52.    
    53.    
    54.    
    55.     void GenerateLightmappingUVs() {
    56.         MeshFilter mf = _target.GetComponent(typeof(MeshFilter)) as MeshFilter;
    57.        
    58.         // make null check because if not enough meshes are present no combined mesh would have been created!
    59.         if (mf != null) {
    60.             Unwrapping.GenerateSecondaryUVSet(mf.sharedMesh);
    61.         }
    62.     }
    63.    
    64. }
    65.  
    Note: While the script still gives you the opportunity to use it with meshes with multiple materials (which will effectively generate multiple new gameObjects), this is not supported in this version, you might get errors. If you need that, feel free to build that yourself or let me know, shouldn't be hard to add.
     
  3. stimuli

    stimuli

    Joined:
    Mar 6, 2013
    Posts:
    1
    This script is perfect. Well done! Why this isn't bundled with the standard assets is beyond me (instead of the broken CombineChildren that is).
     
  4. Louis-N-D

    Louis-N-D

    Joined:
    Apr 17, 2013
    Posts:
    224