Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

CombineMeshes and retain Lightmap (how i got it to work)

Discussion in 'Scripting' started by advo, Oct 13, 2020.

  1. advo

    advo

    Joined:
    Apr 6, 2016
    Posts:
    14
    Hi All,

    I've seen various questions on forums on CombineMeshes not retaining lightmap details (over and above negative feedback on the CombineMeshes documentation page). I actually managed to get this working and wanted to summarize what I did here. I hope people find this useful.

    Background:
    1. This is all done in URP and Unity 2019.3.13f1
    2. I baked my lightmaps and saved the lightmap data to individual prefabs using this script https://github.com/Ayfel/PrefabLightmapping. This script helps to save lightmap data to the origial prefabs, so that when I instantiate prefabs at runtime, the prefab scene instances retain the lightmap data.
    3. My prefabs are instantiated at runtime, but to improve performance i wanted to also combine the meshes of these prefabs at runtime do reduce my Batches count. I am the unity Mesh.CombineMeshes function, this is where it started to "not work" for a lot of people as the main problem was that although the Meshes combined successfully, the lightmap data from the individual prefabs was not being carried forward to the combined mesh. https://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html
    Below is a summary of what I did to get step 3 above working:

    I did not use Unwrapping.GenerateSecondaryUVSet(mesh) on the combined mesh. In my experience, this seem to generate another UV for the lightmap, when what I really wanted was the lightmap UVs that were auto generated by Unity upon import of the individual meshes of the individual prefabs (Mesh model import settings). The solution of using this GenerateSecondaryUVSet method was recommended by the following link but did not work for me:
    I had to manually set the lightmapScaleOffset value of the combine array before passing it to the CombineMeshes function. Something like this:

    combine[i].lightmapScaleOffset = filter.gameObject.GetComponent<MeshRenderer>().lightmapScaleOffset;
    mesh.CombineMeshes(combine, true, true, true);

    I got this as a clue as i looked at the documentation that stated Set hasLightmapData to true to transform the input Mesh lightmap UV data by the lightmap scale offset data in CombineInstance structs. The Meshes must share the same lightmap texture. Doc link: https://docs.unity3d.com/ScriptReference/Mesh.CombineMeshes.html

    The renderer in the object holding the combined mesh, needs to have its lightmapindex value filled manually. It is only when i did this, did the lightmap image in the inspector on the "Mesh Renderer" component of the gameobject holding the combined mesh... If i had skipped this manual lightmapindex assignment, the renderer component would not show a lightmap image in the inspector. This also assumes all your original meshes that were combined, were originally using the same lightmap with index of 0.
    1. renderer.lightmapIndex = 0;

      See screenshot below (in play mode) the baked lightmap is populated in the renderer because i set lightmapIndex manually.
    • upload_2020-10-13_11-44-7.png
    Your gameobject holding the combined mesh, needs to be marked as static. Without this, the "lightmapping" dropdown option would not even appear in the inspector. See screenshot below. Note this is a screenshot of the same gameobject as the previous screenshot, except that the below is not in Play mode.
    • upload_2020-10-13_11-42-47.png
    I hope some of us find this post useful.

    Kevin
     
    mgear, sewy, DanjelRicci and 2 others like this.
  2. Oivin

    Oivin

    Joined:
    Jan 23, 2016
    Posts:
    3
    First of all, thank you so much for this information.
    I have a problem, however. I'm combining the meshes in edit mode (because I don't need to instantiate) It works fine seemingly, but when I press play, the lightmap gets de-assigned permamnently... Any idea what causes this?

    Before pressing play. The stone meshes are combined, and the lightmap has carried over properly (as seen in the green circles)
    before.png
    When pressing play, the light map disappears. The setttings are switched to using light probes instead. If I try to re-bake lights with the combined mesh again doesn't look proper.
    after.png

    EDIT:
    For now at least I opted to combine the meshes at runtime in Awake(). It does increase load times ever so slightly, but at least it works. You have to disable static on them before building though, otherwise Unity will combine some of them on build and break your script.

    EDIT 2: If anyone is wondering why not let Unity combine these meshes on build - it's because the stones that make up this wall are very unoptimized and Unity doesn't batch them properly as can be seen in a debug build's frame debugger.
     
    Last edited: Jan 27, 2021
  3. DanjelRicci

    DanjelRicci

    Joined:
    Mar 8, 2010
    Posts:
    304
    I am having the same issue as Oivin. Previously I let the game combine meshes on Awake and it was fine, but now I need to combine them in Editor because I do further operations on my meshes before they are ready to go for Play mode, and they lose the lightmap when pressing Play. I noticed any of the combined objects will lose the lightmap right away when trying to duplicate it in Editor.

    I'm not having any luck with the few search results around this issue...
     
  4. freso

    freso

    Joined:
    Mar 19, 2013
    Posts:
    72
    Something is definitely not right. Using 2020.3.19.

    We should not have to set the index manually. Also the index is not saved, and needs to be set on Awake. (that's why it's disappearing).

    Code (CSharp):
    1. public void CombineMeshes(CombineInstance[] combine, bool mergeSubMeshes = true, bool useMatrices = true, bool hasLightmapData = false);
    I'm using this on a model that Unity has imported with "generate lightmap UV:s". The meshes in that model has two UV:s.
    When looking at the generated mesh in the inspector, it also has two UV:s, but when adding hasLightmapData=true the generated mesh gets 3 UV:s. Huh? Also, when showing the "UV Layout" in inspector, there is a weird grid in a grid. Eh?

    Maybe @Kuba from https://forum.unity.com/threads/generate-lightmap-uvs-for-editor-combined-mesh.495158/ has something wise to say.
     
  5. sewy

    sewy

    Joined:
    Oct 11, 2015
    Posts:
    135
    2019.4LTS, standard pipeline, same problem - had to set lightmapIndex and lightmapScaleOffset myself, thanks @advo
     
  6. ShriPlusPlus

    ShriPlusPlus

    Joined:
    Dec 13, 2014
    Posts:
    1
    Thanks for the advice Advo. Super useful!

    Just reporting that I am also facing the same issue as the others above. When I press play, the baked lightmap of the combined mesh is lost.

    I'm using Unity 2020.3.27f1, standard render pipeline.
     
  7. ButtCleaves

    ButtCleaves

    Joined:
    Jun 17, 2015
    Posts:
    4
    Code (CSharp):
    1.  
    2.     Vector2[] uv2 = mesh.uv2;
    3.     Vector4 o = meshRenderer.lightmapScaleOffset;
    4.     Vector2 scale = new Vector2(o.x, o.y);
    5.     Vector2 move = new Vector2(o.z, o.w);
    6.  
    7.     for (int i = 0; i < uv2.Length; i++)
    8.     {
    9.         Vector2 lightmapUV = uv2[i] * scale + move;
    10.     }
    11.