(Guide) How to use Multi-channel Signed Distance Field?

I recently found an interesting technique in GitHub.



It has a lower resolution than the existing Signed Distance Field, but it is more pronounced and accurate.
It’s a new alternative to great vector graphics, and I’m looking for a way to use it.

But there is some confusion about how shaders are handled.
GitHub repository has an example, but I do not know exactly how to display the processed output.

I’ve done this in shadertoy.com, but it’s just being processed as the original pixels.
I want to know what to do if I’m using it wrong.

What is the right way to use it?

2 Likes

where is the example shader you mentioned?

There is a sample shader in README.md in GitHub repo.

Amm maybe I got almost correctly on below result I think.

https://www.shadertoy.com/view/XtfyWH

Okay, now I’m got stuck at porting to Monogame effect HLSL.


HLSL (base of SpriteEffect template)

#if OPENGL
	#define SV_POSITION POSITION
	#define VS_SHADERMODEL vs_3_0
	#define PS_SHADERMODEL ps_3_0
#else
	#define VS_SHADERMODEL vs_4_0_level_9_1
	#define PS_SHADERMODEL ps_4_0_level_9_1
#endif

Texture2D SpriteTexture;

sampler2D SpriteTextureSampler = sampler_state
{
	Texture = <SpriteTexture>;
};

struct VertexShaderOutput
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR0;
	float2 TextureCoordinates : TEXCOORD0;
};

float  pxRange = 5.;
float4 bgColor = float4(1, 1, 1, 1);
float4 fgColor = float4(0, 0, 0, 1);
float2 textureSize = float2(128, 128);
float scale = 0.1;

float median(float r, float g, float b) {
	return max(min(r, g), min(max(r, g), b));
}

float4 MainPS(VertexShaderOutput input) : COLOR
{
	//textureUV = vec2(textureSize(iChannel0, 0));
	
	float2 pos = input.TextureCoordinates;
	SamplerState samplerState
	{
		Filter = Point;
		AddressU = Wrap;
		AddressV = Wrap;
	};

    float2 msdfUnit = pxRange/float2(textureSize);
    float3 sample = (tex2D(SpriteTextureSampler, pos) * input.Color).rgb;
    float sigDist = median(sample.r, sample.g, sample.b) - 0.5;
    sigDist *= dot(msdfUnit, 0.5/fwidth(pos));
    float opacity = clamp(sigDist + 0.5, 0.0, 1.0);
    return lerp(bgColor, fgColor, opacity);
}

technique SpriteDrawing
{
	pass P0
	{
		PixelShader = compile PS_SHADERMODEL MainPS();
	}
};

C# (in Draw method)

//test is Texture2D.
spriteBatch.Begin(effect:MSDFshader);

spriteBatch.Draw(test, test.Bounds, Color.White);

spriteBatch.End();

It’s nothing is displayed.
What did I do wrong?

you need to enable HiDef at the beginning of your code,
graphics.GraphicsProfile = GraphicsProfile.HiDef;

make sure you have that

Thank you for your reply, @kosmonautgames!

But this problem is… oops… this was a matter of shader code and my mistake :frowning:
The global variable of the shader was caused by the fact that the initial value was not entered when the value was declared.

I still have problems with the shader, but I’ve seen it render the MSDF texture nicely in vector style!

I will post the modified HLSL and C# code tomorrow because I do not have time today :smiley:

1 Like

this problem is

A global variable was a problem even if it was declared.

So I modified it to include color.

Then this problem appeared this time!
This was what happened to me till yesterday.

Looking at the MSDF texture, I see that it only happens in full magenta(#FF00FF)

I saw the pipeline tool because I knew it would never happen if it was normal.

There was exactly magenta in ColorKey, and I wondered if I changed it to yellow (# FFFF00) in MSDF texture.

finally…!

So, I turned it off and tested it.

YouTube video : https://youtu.be/fuv7HjWWAd4
YES I DID IT!

The MSDF technique is definitely a good technique, I think it would be good for the Monogame community!
So I decided to share this project file to my GitHub repository.

I hope this results will be of help to the good Monogame project.

Thanks! :smiley:

2 Likes

Looking good! Would love to see some benchmarks for this. If it’s good enough, maybe it would be a good fit for MG core. I think it would be great to have an alternative solution for fonts that handles scaling well at the cost of performance.

1 Like

@Jjagg same thing my opinion, thanks! <3

I have just added on README.md, how to convert SVG to MSDF texture with Chlumsky’s MSDF converter.

If your SVG file can not be converted, refer to my repository.


1 Like

I have just found helpful generator.
If you want to use font with msdf technique, use soimy’s msdf-bmfont generator.

It’s need Node.js NPM.

1. Install Node.js
2. If you finished install, use CMD to check they are successfully installed.
   >npm version
3. download msdf-bmfont, and extract to folder.
4. return to CMD, follow to this command. (use drag and drop or paste path.)
   >npm install <extracted folder root> -g
5. then, npm will install the package.
6. thats it! msdf-bmfont guideline is in repository README.md.