# Unity shader to pick 1 of 2 base colors for individual instances (picture)

I am building this scene in 3D using Unity 2019.3.13's Universal Render Pipeline. I have a block prefab that I want to instance, but I want to choose which are yellow and which are blue (you can see the materials are basically the same). How can I write a shader that will allow me to pick either yellow or blue in the editor for each one? Is this possible? What is the most optimal way to make dozens of identical blocks where the color is different for specific instances?

(I would prefer a script to a graph, something with a simple switch/boolean input and hex values: yellow: e4c658 blue: 32676a

• Presumably you considered using MaterialPropertyBlocks for this? – DMGregory May 15 '20 at 0:04

If you just want chequerboard alternation, we can do this with a single material, and save you making/positioning/rendering individual cubes.

You can see from the selection wireframe in this screenshot, we're drawing far fewer triangles this way than if every cube was a separate mesh with a distinct material from its neighbours. That also means less overdraw from interior faces that we never see.

Here I assume that each of your cubes is 1 unit wide, and they're placed at integer coordinates in world space. We can scale/shift the effect if you need a different grid alignment though.

Shader "Custom/Chequer Volume"
{
Properties
{
_Color ("Color", Color) = (0.8941,0.7764,0.3450,1)
_OtherColor("Other Color", Color) = (0.1960,0.4039,0.4156,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.7
_Metallic ("Metallic", Range(0,1)) = 0.0
}
{
Tags { "RenderType"="Opaque" }
LOD 200

CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows

// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0

sampler2D _MainTex;

struct Input
{
float2 uv_MainTex;
float3 worldPos;
float3 worldNormal;
};

half _Glossiness;
half _Metallic;
fixed4 _Color;
fixed4 _OtherColor;

// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
// #pragma instancing_options assumeuniformscaling
UNITY_INSTANCING_BUFFER_START(Props)
// put more per-instance properties here
UNITY_INSTANCING_BUFFER_END(Props)

void surf (Input IN, inout SurfaceOutputStandard o)
{
float3 inside = round(IN.worldPos - 0.1f * IN.worldNormal);
float parity = abs(fmod(inside.x + inside.y + inside.z, 2.0f));

fixed4 color = lerp(_Color, _OtherColor, parity);

// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

• Hey, Gregory, how are you? This is awesome, but my blocks have bevels and the topology is slightly more complicated than I led on. I simplified the problem for brevity. I decided to create "prefab variants" where the only difference is the material. I don't like having two materials where the only difference is color though... ... yes, I will see if this looks good. I will use Blender to bake Normal and AO maps from a hi-res version. – hatinacat2000 May 17 '20 at 8:00
• I've also tested this with a bevelled cube and it worked in that case too. That said, two separate materials is likely to also be fairly efficient, since all the blues can be drawn together in one batch, followed by all the yellows in a second batch. – DMGregory May 17 '20 at 8:21