- Home /
Vertex Color Optimization
Hi all!
I have an optimization idea which I would like to share and get some feedback on.
The art style for my game is that most objects flat color rather than textured. I have written a Standard Shader which takes in vertex color and does the following (pseudocode):
Metallic = vertexColor.y;
Smoothness = vertexColor.z;
Albedo = (uses vertexColor.x to sample a color from a 16x16 palette, which is the _MainTex of the material)
With this system, I should be able to render pretty much every object in my scene using the same material - as albedo, metallic and smoothness are mapped to the vertex color rgb. I have a small script that can assign "false" color to the meshes in the editor.
Am I clever or have I missed something? I have heard that less switching of materials during the draw calls is a good thing. So far I don't have much content in my game, and I'd like to know if this is viable before I lock hundreds of assets into it. I like the workflow because assigning vertex colors feels less messy than juggling a million materials, and if it saves a bit of overhead that would be nice too. If it is very slow or inefficient for some reason which I haven't been able to figure out, it would be very appreciated if you let me know!
Thank you ~
Answer by Bunny83 · Jun 02, 2018 at 10:22 AM
Well, if 256 colors are enough for you, yes it's possible that way. Though it would be simpler to use a 256x1 texture as you don't have to do the grid mapping. Also make sure your palette texture is set to "point" and that you sample the center of each texel. So just add "1/512f" the normalized index. The index for each vertex color would be index/256f
where index should be in the range of 0 - 255. Of course you can do the half pixel offset already within the index. So index "12" would become 12.5 / 256
or (index + 0.5f) / 256f
Answer by JLJac · Jun 02, 2018 at 12:40 PM
Thank you for your answer!
Okay, I'll go ahead and try it then :) As for the texture, I thought square textures where preferable? Or that has no impact with a tiny texture like this?
256 colors would be enough for me yeah - but I'm not using the alpha channel of the vertex colors so technically I have a few more bits of information I could pass on to the shader if I wanted.
Should I worry about dynamic batching taking a hit as mesh data gets effectively doubled? There's a clear risk some of my meshes will be bumped up above the 900 vertex attribute limit - but I think that might be worth it if the material count is basically decimated or more...
If things work out I'll post the false color assign script and the shader so that others can enjoy single material vertex color rendering ~~~
The shader:
Shader "Custom/BaseEightBitVertex" {
Properties{
_$$anonymous$$ainTex("Albedo (RGB)", 2D) = "white" {}
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
CGPROGRA$$anonymous$$
#pragma surface surf Standard vertex:vert fullforwardshadows
#pragma target 3.0
struct Input {
//float2 uv_$$anonymous$$ainTex;
float3 vertexColor; // Vertex color stored here by vert() method
float2 metallicSmooth;
};
struct v2f {
float4 pos : SV_POSITION;
fixed4 color : COLOR;
};
sampler2D _$$anonymous$$ainTex;
void vert(inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input,o);
o.vertexColor = tex2Dlod(_$$anonymous$$ainTex, half4(frac(v.color.x*15.0), floor(v.color.x*16.0) / 16.0, 0, 0));
o.metallicSmooth = v.color.yz;
}
void surf(Input IN, inout SurfaceOutputStandard o)
{
o.Albedo = IN.vertexColor;
o.$$anonymous$$etallic = IN.metallicSmooth.x;
o.Smoothness = IN.metallicSmooth.y;
o.Alpha = 1;
}
ENDCG
}
FallBack "Diffuse"
}
Texture must be 16x16, point filter mode, and set to NO CO$$anonymous$$PRESSION, or you'll get funky colors