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

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:

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*.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](https://docs.unity3d.com/ScriptReference/CombineInstance.html) 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._
*- ```renderer.lightmapIndex = 0;```*
*See screenshot below (in play mode) the baked lightmap is populated in the renderer because i set lightmapIndex manually.*
*- ![6411756--716163--upload_2020-10-13_11-44-7.png|730x625](upload://qc6iHapLDoqPuQKyrpAP7J7kufi.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._
*- ![6411756--716160--upload_2020-10-13_11-42-47.png|736x518](upload://h9MCICV9mzAtvDxeUg2F0hI6fys.png)*
*I hope some of us find this post useful.*
*Kevin*
5 Likes

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)


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.

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.

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…

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).

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 Generate Lightmap UVs for Editor Combined Mesh has something wise to say.

2019.4LTS, standard pipeline, same problem - had to set lightmapIndex and lightmapScaleOffset myself, thanks @advo

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.

    Vector2[] uv2 = mesh.uv2;
    Vector4 o = meshRenderer.lightmapScaleOffset;
    Vector2 scale = new Vector2(o.x, o.y);
    Vector2 move = new Vector2(o.z, o.w);

    for (int i = 0; i < uv2.Length; i++)
    {
        Vector2 lightmapUV = uv2[i] * scale + move;
    }

I had the same problem preserving edit-time MeshCombined lightmaps. Got it working correctly in the editor with the above advice, but on reload the lightmaps were gone again. I fixed it by setting the lightmapIndex to zero AGAIN on init.

My guess is that it’s because the MeshCombined objects are not listed in the lightmap metadata, they are frankensteined together from objects that WERE lightmapped. Unity presumably checks objects against the lightmap metadata and attempts to “correct” the lightmapindex on load.