Depends on what you mean by “batching”. In Unity, batching usually refers to static and dynamic batching. As I described in the post @Lo-renzo linked to , batching combines multiple meshes into a single pre-transformed into world space mesh. Any connection to the original meshes and their transform matrices is gone at this point, it’s now a single mesh with a single material on it. When it needs to be rendered Unity just has to tell the GPU to use the single material, and then render the mesh. There’s only one unity_ObjectToWorld matrix used on a batched mesh, any batched mesh, and it’s an identity matrix: no scale, no rotation, no translation. It assumes the mesh is being rendered placed at the center of the world, because it is.
There’s no point in batching two meshes with different materials in this way because Unity would have to send the material settings to the GPU, render the part of the batched mesh with that material, then send the second material settings, and render the other part of the mesh. Which is exactly what it has to do to render two meshes anyway.
Understand the most expensive part here for the GPU is having to tell it “hey, we need to change some material settings”.
Now if you wanted to, you could have an array of transform matrices you set on the material, and each vertex of the mesh could store the index to the transform matrix. And you can have other arrays for other material properties use the same index. This is actually what Keijiro’s Kvant Spray does (though instead of arrays the transform matrices and material properties are stored in textures).
So why doesn’t Unity do this by default?
Because it requires completely custom shaders to use. Ones that wouldn’t work on a normal mesh.
The advantage of Unity’s batching approach is the original material that was on the individual meshes “just works” on the batched mesh and the original mesh with no modifications, as long as the original material didn’t require knowing the original transform matrix or original local space vertex positions. And most of the time they don’t. None of Unity’s built in shaders require knowing any of that.
Also remember the batching systems have been around for well over a decade now. The batching systems date back to fixed function shader days, meaning on some platforms it wasn’t even possible to have a shader that required that data. But this batching system would still work.
Now what you’re talking about with having multiple transform matrices or material properties that can change per mesh is called instancing. This is different than batching, and has different limitations. Those limitations exist because of how GPUs were setup to work, not because of Unity. There are commands that tell a GPU “render x of this one mesh using this one material”. The GPU then automatically passes along an index to the shader for each instance of the mesh being rendered, and you can use that to look up into an array of values. This is a more recent system in Unity, only added about 5 years ago. And it still requires custom shaders to make use of it, but they made sure to include macros to help make it easier to implement.