I’m trying to optimize my game for draw calls by combining all my materials (one for each texture) into one material. However the way I am doing it is not optimal and shifts a lot of work into the frag (or surf) function.
I’d appreciate any help with getting this working in an optimal way - for example moving the texture switching into the vert function.
Right now I’m following this guy’s idea here:
Which boils down to:
- On each object, set the mesh vertex colors
Mesh mesh = GetComponent<MeshFilter>().mesh;
Color[] colors = new Color[mesh.vertices.Length];
... //actually populate the colors
mesh.colors = colors;
- In the shader structs for output and input, define a color variable
struct vertexInput {
...
half4 colors : COLOR;
...
}
struct vertexOutput {
...
half3 vertexColor : COLOR;
...
}
- In the shader vert function, populate the color from the vertex into the output struct
vertexOutput vert(vertexInput v) {
vertexOutput o;
...
o.vertexColor = v.colors.xyz;
...
return o;
}
- In the shader frag function (or surf function), switch textures based on the color’s x variable
fixed4 frag(vertexOutput i) : COLOR {
...
fixed4 tex;
if(i.vertexColor.x > 0.5) {
tex = tex2D(_MainTex, uv);
} else {
tex = tex2D(_OtherTex, uv);
}
...
}
Extrapolate that out for switching between 10 or so textures.
Even the guy in the video says that it is not optimal do do this conditional switch in the frag function since it will need to be performed once per pixel. He recommends doing it in the vert function. But if I determine in the vert function which texture I want to use, how do I pass this on to the frag function?
-
Ideally I would like to define a variable for the texture in the output struct, populate that in the vert function and use it in the frag function. But as per the answer to this question
opengl - GLSL sampler2D in struct - Stack Overflow
they seem to be saying that it is impossible to do this since a texture / sampler is an opaque data type. -
It would be even better if I could have an array of textures and convert the color’s x variable into an array index using just math. Something like this:
fixed4 tex;
sampler2D textures[2] = {_MainTex, _OtherTex};
int textureIndex = (2 * vertColors.x) - 1; //assuming the x value is always 0.5 or 1.0
sampler2D myTex = textures[textureIndex];
tex = tex2D(myTex, uv);
But then I get the error “sampler array index must be a literal expression” which as per the answer to this question
https://www.gamedev.net/forums/topic/687522-is-it-possible-to-pass-an-index-to-a-texture-array-through-instancing/
seems to mean that it is also impossible for a shader to use any non-hardcoded variable to get something from an array.
-
That post winks about DirectX12 but my project is for mobile. I have also heard about unity’s Texture Arrays
Unity - Manual: Texture arrays
but my textures are not all of the same size. -
I guess there is also the texture atlas + UV Mapping route if I were to go in and modify all my meshes, but my game geometry is largely built out of different sized cubes, all of which use the same mesh…
I’m exhausted! Is there a solution to this hiding around anywhere?