Hey. I'm looking to make a shader that uses vertex colors as its main element, with a special case for a "color key" effect (so i can change some colors on the fly with code). Normally I'd use the alpha channel of vertex colors for intensity of the color key (i dont plan on using inherently-translucent meshes), but it's not easy to do alpha with my new workflow so I'm trying to use a "magic color" solution. (ie full white faces are color keyed, everything else displays its normal vertex colors) So I've managed to get a vertex color shader working but for some reason the source colors are altered in a way that corrupts these magic colors in a noisy pattern. Here's how the model looks with raw vertex colors (the top white border has 100% white vcolor) https://imgur.com/a/vGlG6Ca Here's how it looks with the color keying https://imgur.com/a/YS6zZ1H And here's the shader code I have https://pastebin.com/7xANDtTD I've also tried a simpler fragment shader approach but got the same result https://pastebin.com/BWCHm5nN Moving around with a flying camera it loosely resembles z-fighting (doesn't make sense, there's only one mesh and no faces in it overlap, i double checked for sanity). The faces are properly culled from the back too. In fact, the pattern seems related to distance from viewing point BUT maybe also normals? https://imgur.com/a/EaumP58 https://imgur.com/a/fIqmkqq I've tried literally passing float4(1.0, 1.0, 1.0, 1.0) from the vertex shader (still affected, but on the whole mesh ofc) The only time it works as intended is if I change the if statement to look for values above 0.99 or something, but that's obviously a really poor "solution". Any help would be greatly appreciated, thanks! I'm using Unity 2018.3.3f1
That is actually the solution. The problem is the combination of floating point math and barycentric interpolation means that "1.0" will can slightly below and slightly above "1.0" across the face even when all 3 vertices of a triangle are the same value. For example, a point on a triangle that's right near the center of the triangle will be roughly equal to: VertA * (1/3) + VertB * (1/3) + VertC * (1/3) Using arithmetic we know those should add up to 1.0 if all 3 vertex values are 1.0, but with floating point math it might equal 0.9999999, or 1.000001! This shader passes a material property value via the vertices and then tests if the value is equal (green), less than (red), or greater than (blue) the material's property. Code (CSharp): Shader "Interpolation Error" { Properties { _Value ("Value", Float) = 3.0 } SubShader { Tags { "Queue"="Transparent" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; // nointerpolation // uncomment this line to remove interpolation from the below value float value : TEXCOORD0; }; float _Value; v2f vert (appdata_full v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.value = _Value; return o; } float4 frag (v2f i) : SV_Target { float4 col = float4(0,1,0,1); if (i.value < _Value) col = float4(1,0,0,1); else if (i.value > _Value) col = float4(0,0,1,1); return col; } ENDCG } } } So you really do need to do something like " >= 0.99". I'd suggest using something like this: // color values are 8 bit, so they are limited to steps of 1/255 float interpolationErrorFudge = 0.5 / 255; // half a step of fudge factor // tests if all component values are > 0.0 if( all(i.color.rgb - (1.0 - interpolationErrorFudge)) ) { // do stuff }