Skip to content

feat: Dynamic Runtime Rasterized MSDF Sprite Font#3055

Draft
yuechen-li-dev wants to merge 66 commits intostride3d:masterfrom
yuechen-li-dev:runtime-msdf-font
Draft

feat: Dynamic Runtime Rasterized MSDF Sprite Font#3055
yuechen-li-dev wants to merge 66 commits intostride3d:masterfrom
yuechen-li-dev:runtime-msdf-font

Conversation

@yuechen-li-dev
Copy link
Copy Markdown

PR Details

This PR adds an experimental runtime MSDF font path to Stride’s sprite font system.

Screenshot 2026-02-04 003111

Introduction

Stride’s current sprite font rasterization options each have trade-offs. Dynamically generating MSDF glyphs on-demand is the common approach in modern engines (e.g., Unity/Unreal): it combines the benefits of Stride’s runtime rasterized fonts (large character sets like CJK) with offline SDF/MSDF advantages (smooth edges at high resolution, easy scaling) with minimal downsides.

Implementation

Dynamic MSDF generation differs substantially from Stride’s existing static SDF pipeline.

  • Uses SharpFont (already a Stride dependency) to extract glyph outlines on-demand when glyphs are requested at runtime.
  • Generates MSDF textures asynchronously via a bounded Channel + worker pool, then uploads into the font atlas.
  • The MSDF rasterizer is intentionally modular / swappable to keep the pipeline future-proof.

Rasterizer backends

Two managed, cross-platform MSDFGen ports are included (no P/Invoke):

Also included:

  • Two debug rasterizers:
    • a simple pattern output backend
    • an outline diagnostic backend

Notes / limitations

  • "Default Size" parameter is used for baking, keep it relatively large (64+) for best results.
  • Some fonts (especially those with overlapping / self-intersecting contours) can produce repeatable MSDF artifacts (notably in punctuation/CJK). Current workaround: preprocess fonts in FontForge (Remove Overlap / Simplify / Correct Direction). This keeps runtime lightweight and avoids bundling heavy geometry cleanup.
  • Game Studio “Play” vs running from Visual Studio can differ in dependency deployment. Ensure the MSDF backend assemblies are present in the runtime output; if needed, run the game via VS at least once so dependencies get copied/resolved. Otherwise, fonts may render in the editor but not in-game.
  • Thumbnail preview for runtime MSDF fonts is currently blank; I wasn’t able to find a clean fix yet.

Testing

  • Verified glyph generation + atlas upload in the editor.
  • Verified runtime behavior when launched from Visual Studio.
  • Used debug backends to validate atlas upload/sampling independently of MSDF generation.

Core files:

  • RuntimeSignedDistanceFieldSpriteFont.cs
  • SharpFontOutlineExtractor.cs
  • MsdfGenCoreRasterizer.cs (MSDFGen-Sharp backend)
  • RemoraMsdfRasterizer.cs
  • Pipeline glue (MsdfGenerationPipeline.cs, etc.)

Thanks. This took a lot longer than I thought it would.

Comparison

Existing Runtime Rasterized Font:
image
New Runtime MSDF Font:
image

Related Issue

#2584

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have built and run the editor to try this change out.

yuechen-li-dev and others added 26 commits January 28, 2026 20:09
This reverts commit 0dc668c.
…-in-runtimesigneddistancefieldspritefon

Remove runtime SDF bake size plumbing and use SpriteFont.Size for glyph generation.
…ey cache into ConcurretDictionaries to future-proof multithreaded calls in the future.
@yuechen-li-dev
Copy link
Copy Markdown
Author

@dotnet-policy-service agree

@Eideren
Copy link
Copy Markdown
Collaborator

Eideren commented Feb 4, 2026

We already have an offline SDF option - but I understand that the reason you implemented this feature is because non-latin character sets tend to be very large and require a high resolution. Offline SDF we currently have wouldn't work because it would have to cover multiple thousands of characters with a fairly high resolution, potentially blowing out build sizes.

Definitely cool to see, now, is there a particular reason why this PR specifically sidesteps using most of the logic already setup for offline SDF ?

Also, as it stands, the limitations seems a bit like a show stopper. Our engine already has enough quirk as it is, best to fix those before we merge this in

@Eideren Eideren added the area-UI label Feb 4, 2026
@Eideren Eideren changed the title Add Dynamic Runtime Rasterized MSDF Sprite Font feat: Dynamic Runtime Rasterized MSDF Sprite Font Feb 4, 2026
@Kryptos-FR
Copy link
Copy Markdown
Member

That's also my take. Our project is open source so our direct consumption is fine. For users of the engine, it falls under transitive dependency which is also covered by the opensource license.

We just need to be careful and monitor any change in licensing terms.

@xen2
Copy link
Copy Markdown
Member

xen2 commented Apr 11, 2026

FYI I have merged #3129 and #3131 today.

Question: can this new msdfgen C# implementation be used as a replacement for msdfgen.exe at asset compilation time too?
That would be one less dependency blocking us the way for cross-platform asset compilation.

@yuechen-li-dev
Copy link
Copy Markdown
Author

FYI I have merged #3129 and #3131 today.

Question: can this new msdfgen C# implementation be used as a replacement for msdfgen.exe at asset compilation time too? That would be one less dependency blocking us the way for cross-platform asset compilation.

Easily. You can just call the rasterizer, which is designed to be reusable, or implemented it with the library. It's one of the key blockers before implementing something like rounded corner rectangles in the UI, which relies very heavily on SDF.

https://github.com/yuechen-li-dev/stride/blob/runtime-msdf-font/sources/engine/Stride.Graphics/Font/RuntimeMSDF/MsdfGenCoreRasterizer.cs

@xen2
Copy link
Copy Markdown
Member

xen2 commented Apr 11, 2026

FYI I have merged #3129 and #3131 today.
Question: can this new msdfgen C# implementation be used as a replacement for msdfgen.exe at asset compilation time too? That would be one less dependency blocking us the way for cross-platform asset compilation.

Easily. You can just call the rasterizer, which is designed to be reusable, or implemented it with the library. It's one of the key blockers before implementing something like rounded corner rectangles in the UI, which relies very heavily on SDF.

https://github.com/yuechen-li-dev/stride/blob/runtime-msdf-font/sources/engine/Stride.Graphics/Font/RuntimeMSDF/MsdfGenCoreRasterizer.cs

Great to hear that!
Do you think it could also be added as part of this PR?

@yuechen-li-dev
Copy link
Copy Markdown
Author

FYI I have merged #3129 and #3131 today.
Question: can this new msdfgen C# implementation be used as a replacement for msdfgen.exe at asset compilation time too? That would be one less dependency blocking us the way for cross-platform asset compilation.

Easily. You can just call the rasterizer, which is designed to be reusable, or implemented it with the library. It's one of the key blockers before implementing something like rounded corner rectangles in the UI, which relies very heavily on SDF.
https://github.com/yuechen-li-dev/stride/blob/runtime-msdf-font/sources/engine/Stride.Graphics/Font/RuntimeMSDF/MsdfGenCoreRasterizer.cs

Great to hear that! Do you think it could also be added as part of this PR?

It is already part of the PR as this is a necessary functionality for this feature to work. After this, I think msdfgen.exe can just be removed if the old static SDF font was migrated to the new rasterizer or removed altogether.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants