The “flat” qualifier you want doesn’t exist. There *is* a `flat`

interpolation modifier for GLSL, which is the equivalent of `nointerpolation`

in HLSL. But these don’t do what you’re describing. Instead they use one value over the inter triangle (hence “no interpolation” or “flat”). However it gets that value from the “invoking vertex” of the triangle.

Unfortunately which vertex is considered the “invoking” vertex isn’t consistent between APIs or devices, and is probably not going to automatically be the vertex you want it to be. Best case is each “square” is a solid color, no diagonals. Worst case you get some diagonals, but on transition edges you get every other triangle being different.

However there *is* a way to get what you want. Instead of interpolating the actual colors between vertices, interpolate a value of 0.0 or 1.0 based on if you want one color or the other. Then in the shader round the weight and lerp between the two colors which are set as material properties. You won’t get diagonals anywhere but where the geometry has a diagonal, but you *can* have diagonals.

Even better, you can paint the weights in a kind of blurry manner, then you can get diagonals everywhere!

You can also do a little extra math to get nearly free anti-aliased edges.

```
Shader "Unlit/Sharp Blend Interpolation"
{
Properties
{
_ShapeTex ("Shape", 2D) = "grey" {}
_ColorA ("Color A", Color) = (1,0,0,1)
_ColorB ("Color B", Color) = (0,0,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float weight : TEXCOORD0;
};
sampler2D _ShapeTex;
float4 _ShapeTex_ST;
float4 _ColorA, _ColorB;
v2f vert (appdata_full v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
// getting the weights from a random texture because I didn't want to have to import in a vertex painted mesh
o.weight = tex2Dlod(_ShapeTex, float4(TRANSFORM_TEX(v.texcoord.xy, _ShapeTex), 0, 0)).r;
// uncomment this to test out what it looks like to use binary values of 0 or 1 for the weight
// o.weight = round(o.weight);
// example of weights stored in the vertex color, how you'd probably _actually_ want to do it
// o.weight = v.color.r;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// preview the weights
// return i.weight;
// anti-aliased sharp weight
float weight = saturate((i.weight - 0.5) / max(0.00001, fwidth(i.weight)));
// lerp between the two colors
return lerp(_ColorA, _ColorB, weight);
}
ENDCG
}
}
}
```

While the above isn’t written using Shader Graph, it’s not a ton of work to translate it to nodes. The confusing bit is `fwidth()`

is the DDXY node. Otherwise use the Vertex Color node as the “weight” and do the 6 nodes worth of math in the frag function.