Ayfel / PrefabLightmapping

Script for saving lightmapping data to prefabs. Used through the Assets tab in Unity. Place your prefbas in the scene with this script at the root. Set up your lighting and in the editor go to Assets->Bake Prefab Lightmaps. After is processed you can now spawn your prefabs in different scenes and they will use the lightmapping from the original scene.
645 stars 90 forks source link

Detail Map in standard Shader stripped in Builds 2019.3 #33

Open smoore2171 opened 3 years ago

smoore2171 commented 3 years ago

I have an older project on 2019.3 I'm trying to get to work with this script.

This works fine while in editor, but in the built game, some nested prefabs using the unity Standard shader that are already baked using realtime GI in the scene show up as unlit as if the lightmap is not applied, both in the prefab being spawned and in the scene that exists (it is the same inner prefab).

This happens whether the prefab was in the scene or spawned (it will go dark as soon as I spawn it). It happens whether or not the objects in the prefab are flagged as static or not. And it happens whether or not I strip all shaders or not (set to custom with everything checked, etc) in settings.

The only thing I notice is the textures are not under resource/*. I'm not sure if they need to be. The other level with a reference to this prefab is not included with the build. I will check just including that to see.

Ayfel commented 3 years ago

I am not understanding quite right the setup. You have baked lighting or real-time GI? Are you in the built in renderer or another scriptable render pipeline? Are you saying parts of the prefab are correctly shown as baked an others not? Do try including the level you bake them in to see if that changes and let me know of the results and the above question pls. Thank you.

smoore2171 commented 3 years ago

so I have a prefab A containing sub prefab B. I place A in an empty scene with script in the root object, have it only do blaked lighting with a directional light set to baked.

I bake the lighting and use the script. So far so good.

I go another scene that contains prefab B but lit with mixed dynamic GI (I was using to see the difference in order to reauthor the baked lighting to make it close to my existing realtime GI lighting) and either place prefab A in it or spawn it at runtime.

In the editor play, the lighting for everything looks correct. If I build the solution, prefab B looks like it gets its lightmap stripped everywhere, both in Prefab A and in the scene in which it is spawned. The last time I tried this, the whole prefab A actually looks like it is not correctly lit as well.

smoore2171 commented 3 years ago

Including the level did not seem to help.

smoore2171 commented 3 years ago

and it is built-in renderer*

smoore2171 commented 3 years ago

I just tested a build of just this prefab A placed in that empty level, and the same behavior is happening so I don't think it is related to the dynamic GI.

smoore2171 commented 3 years ago

I side-by-sided it with a build where the lighting wasn't built at all, and it does seem only the Standard shader is affected.. Other objects in the scene with different shaders are actually getting the lightmaps applied correctly.

smoore2171 commented 3 years ago

I think I've narrowed it down to an existing realtime-only directional light (in addition to the baked-only realtime light) in both scenes. In the editor, these objects, even though they have baked lighting, are still receiving and calculating light from the realtime directional light. For some reason, only for builds, the Standard shader does not take realtime lighting if it has baked lightmaps. I can only imagine this inner prefab is using a shared material or something and it is applying this baked lightmap globally, which explains why the existing objects in the scene get affected.

I suppose I can just have it use the other shader if there isn't a workaround for that.

smoore2171 commented 3 years ago

Switching to another shader that wraps Standard works. I don't know why, but at least I am unblocked

Ayfel commented 3 years ago

Im glad you have a workaround. It is quite a complex setup so I would love to understand the issue and see why it happens, if you could share a project that reproduced the issue I'd be happy to take a look

smoore2171 commented 3 years ago

I'll try to repro in 2021.1 with a simple cube prefab

Ayfel commented 3 years ago

Thanks 2019 is fine too as it is LTS

smoore2171 commented 3 years ago

So I narrowed this down further. It appears there was a bug in just 2019.X versions where detail albedo secondary masks for a material will get stripped in the build for standard shader if using baked lightmaps.

I tested the exact same scenario on a 2019.3 project and a 2021.X project with just a cube prefab and a new standard shader material using a built-in texture as the secondary detail albedo. It gets stripped in the builds for 2019.X but not in the 2021.X, so this issue must have been fixed somewhere along the way. This was making my object look much darker as if it was not getting lightmaps at all, but I confirmed it looked the same as the object without the detail map, which was slightly distinct from completely unlit.

So not an issue with this script it appears, just unity being unity.

smoore2171 commented 3 years ago

I spoke too soon. It appears if I do a normal bake and load the scene with this prefab, the detail mask is kept in the built game. Only if I bake those lightmaps to this prefab does the detail map get dropped. Not really sure how the textures in the material are being modified by this script.

smoore2171 commented 3 years ago

It's this section. There must have been some side effect to setting the shader in 2019.3 that they resolved in 2021... // You have to release shaders. Material[] mat = info.renderer.sharedMaterials; for (int j = 0; j < mat.Length; j++) { if (mat[j] != null && Shader.Find(mat[j].shader.name) != null) mat[j].shader = Shader.Find(mat[j].shader.name); }

        Removing this fixes the issue in 2019.3
smoore2171 commented 3 years ago

Idk if you want to wrap that in unity version preprocessors, as I'm not clear on what resetting the material shaders was doing. It claims it is releasing shaders, but idk how the pool of shaders the "Shader.Find(" pulls differs from the shader it was pointing to at load. For sure this code doesn't cause an issue in 2021, so I'm guessing the eff up was on Unity handling of the = operator for shader and not passing all the params of the material correctly when reloading the shader.

Ayfel commented 3 years ago

So it works fine when removing the section you pointed out?

smoore2171 commented 3 years ago

Correct, but only on 2019.3. On 2021, it worked with and without reloading the shader.

Ayfel commented 3 years ago

Yeah confirmed, this is a Unity issue, the problem is that in some cases I encountered the shader reload is necessary so its not just wrapping it in a preprocessor directive that will fix it, I have to think on it a bit, maybe an option in the script.

I am going to leave this issue open as a reference as well for now and change the title for good measure.

smoore2171 commented 3 years ago

One somewhat hacky workaround is to simply store off all of the material inputs and manually send them back into the shader after reloading it.