Similarly to this thread:
Procedural Border Detection on a Flat Object
You could capture the distance to the nearest point, and calculate the distance to it on the shader:
The artifacts are caused by situations, where the nearest point of the center of the face is a different point than the nearest point to some point of that face:
$\bbox[#000000, 7px]{\color{#f0ff00}{\mathtt{⏺}}}$ yellow dot - the center of the face.
$\bbox[#000000, 7px]{\color{#ffa200}{\mathtt{→}}}$ orange arrow - the nearest point to the center of the face; its position is stored on a face and used in the shader.
$\bbox[#000000, 7px]{\color{#ea00ff}{\mathtt{⏺}}}$ fuchsia dot - example of an evaluated point in a shader.
$\bbox[#000000, 7px]{\color{#ff0000}{\mathtt{→}}}$ red arrow - distance between fuchsia dot and the tip of the orange arrow - that's what calculated inside the shader.
$\bbox[#000000, 7px]{\color{#2aff00}{\tiny{-->}}}$ green dashed arrow - the actual distance you want, but how do you capture this other point? In the link above my approach is to capture not one nearest point of the face, but 3 points, each nearest for one vertex of a triangle (but I still store it on a face so it's not interpolated between points by the shader). You could of course store more more, but at some point you have to consider if subdividing instead isn't cheaper on the resources.