I’ve been working on a custom vert/frag shader in URP to create mapmodes for my tile-based world game.
Currently, my attempt at the mapmodes is just trying to color the entire tile a single color by accessing a StructuredBuffer with the respective value I calculated in a ComputeShader, with the indexes being equivalent to a flattened array of my world grid.
Now, I would only need a way to have each object be able to know their respective tile index so that they can access the buffer and get their color, since all objects use the same material.
I’ve spent a couple of hours attempting to use the vertex streams of the mesh to pass this data, trying both the vertex colors and additiona uv channels as my streams to pass the data, but this hasn’t worked. I assume it’s because the channels that use the : COLOR or : TEXCOORDN semantics automatically get normalized by Unity? I’m not sure though, but all my tiles get the same value regardless.
How could I pass these per-object indexes (which can range from 0 to over 100) to the shader in a way that dosen’t break batching? I don’t think vertex streams seem to be the correct way of going by this.
since you seem to be only using whole numbers, so why not just scale everything down by 100 beforehand? all it would require is one multiply by 100 in shader to bring things back to correct level. if you were trying to pass floats this method would suffer from precision errors, but i don’t think it would effect you since no numbers would be hitting the floating point limit.
I did this while passing the values over the Colors stream and it has worked, and is probably enough for my current use case since I doubt i’d ever need a map with more than 100 tiles in the current state, so thanks for the suggestion!
Even so, I wonder if there isn’t a better of going by this in the future? My current situation is pretty specific since I only need to pass integers, but it still feels quite “Wasteful”, if you will, to have to pass a whole array of Colors to the mesh data even though I only really need access to a single value stored on the x, unless I find different uses for the other channels of the stream.
I’m interested if there would be a “more correct” way of going by this requirement of passing non-normalized per-object data, or even if this entire approach I’ve chosen to go by is wrong. Regardless, your suggestion fits my exact needs right now so thank you very much!
[EDIT]: It seems like doing things this way breaks SRP batching because “the material has a custom buffer override”, even after I switch to using a global buffer by a Shader.SetGlobalBuffer() call, so unfortunately, this might not be a good approach for what I’m looking for. Any help is appreciated.
in BIRP i would use material property blocks, but i’ve heard they have worse performance on the srps. maybe you could store it in the mesh vertex colors without a buffer? i’m not sure if this effects baching negatively though, but i would doubt it since the srp batcher is more based on shader than model.
For anyone coming after this, I managed to solve my current necessity (passing an object index to a shared shader and acessing some sort of buffer using this index) by passing my indexes through the vertex colors with a division to reduce them between the normalized range and re-multiplying them in the vertex stage ,just like POOKSHANK suggested.
As for the following edit to my last post:
This recent post seems to imply that any sort of buffer usage will break the SRP Batcher for the material. Unlike the post, I was using a ComputeBuffer, but got the same error batching message. In the end, I moved away from my compute shader into calculating all the values I need in the CPU and passing them to the shader through a float array with Material.SetFloatArray(), and that has been working for me so far.