So, I discovered that the Frame Debugger does not accurately report all Shader Keywords, at least in the case of the SRP used in 2018.4.2f1. So, while my above screenshot made it appear the two broken batches had no keywords, at least one of them did.
Then I set each one of my different Materials that use specific shaders to occupy a different part of the RenderQueue in increments of 50.
Finally, I created a Dictionary so that each unique keyword combination would receive a “modifier” value, and thus each Shader+Keyword combo would reside in its own unique RenderQueue number. I am assuming there will not be more than 49 unique combos, thus I will not enter another Shader’s designated RenderQueue window. This system could be improved of course, but it works for my purposes.
//This block of code is for more efficient SRP Batching, because a batch will break if Keywords are different
//We group their RenderQueue numbers together based on their keywords
if (newMat.shaderKeywords.Length > 0)
{
var keywords = "";
foreach (var s in newMat.shaderKeywords)
keywords += s + ",";
//Debug.Log(string.Format($"{newMat.shader.name} has additional keywords: {keywords}"));
if (!keywordRenderQueueModifier.ContainsKey(keywords))
keywordRenderQueueModifier.Add(keywords, keywordRenderQueueModifier.Count + 1);
//Debug.Log(string.Format($"keywordRenderQueueModifier[{newMat.shader.name}][{keywords}]={keywordRenderQueueModifier[newMat.shader.name][keywords]}"));
newMat.renderQueue += keywordRenderQueueModifier[keywords];
}
As far as I am aware, modifying the RenderQueue is the only way to manipulate the batcher into not jumping around between things (and thus breaking batches) in a way I don’t understand myself.
Could this have anything to do with Local vs Global Keywords? Total shot in the dark but it sounds like setting a global keyword might effect shaders that do not care about that keyword after the keyword has been set.
Probably wrong but worth a test.
For anyone else who comes across this thread, I just want to add that you can set the inspector to debug mode and see all the keywords that are being saved to your materials. I was able to significantly reduce batches by simply clearing keywords that had been left behind by an earlier shader.
OMG, you’re such a life saver man ! so glad I’ve found your post early in my investigation. This sort of mistake on unity part could’ve taken me couple days to figure out … Also i’m really hard at work trying to find the proper method to actually make a RemoveRemnantKeyword() function to automatically parsed a project … but so far i’m unable to properly access this string apart from the actual .mat file in text format
I’m not convinced these are breaking batching, I couldnt reproduce it, but to remove them all from the materials in the project, I just used notepad++ and this regular expression to find and remove all of the invalid keywords
I’m having this same issue. It can be seen in this 5 consecutive batches, which break even though the frame debugger reports the same keywords for all of them. Using the latest Unity 2021 LTS
I’m on the process of removing keywords from shaders, so the materials used in this cases were created when the shaders had keywords that made them different. I’ve clicked on all the materials and made sure using the debug mode in the inspector that there’s no keywords inside the valid keywords array (all the remaining keywords are set globally, none on the material).
EDIT:
I was able to find the problem.
The batcher breaks in between lightmapped and not lightmapped objects even if the shader doesn’t have #pragma multi_compile _ LIGHTMAP_ON. Having any value in the “lightmap index” variable of the render, which gets set by the lightmapper or can be also set manually, breaks the SRP batcher even though all it should do is set the LIGHTMAP_ON keyword and pass the lightmap, scale and offset parameters (for simple lightmaps at least, dual lightmaps have more stuff but I don’t use them so idk).
This bug should only affect those who use a shader where lightmapping is behind a dynamic branch instead of a different shader variant, which is probably rare, but not impossible. I don’t know if it also breaks in between different lightmap indices, only that it breaks in between lightmapped and not lightmapped independently of the shader having or not LIGHTMAP_ON or other keywords.