1

I'm evaluating Direct2D for research purposes, and while I was at it, I decided to render my usual help text with a DirectWrite custom text renderer, which converts the text to a path geometry in order to add outline (as demonstrated in the DWriteHelloWorld sample on MSDN).

However, some letters have weird "hairs" or "horns" on them (picture: stroke width of 3 and 5).

text outline with different stroke widths

Also tried with other fonts (f.e. Consolas), the effect is the same.

Source code (VS 2015): https://www.dropbox.com/s/v3204h0ww2cp0yk/FOR_STACKOVERFLOW_12.zip?dl=0

Asylum
  • 569
  • 4
  • 21

2 Answers2

2

The solution is as easy as I hoped. The "hairs" are actually caused by the line joints which D2D generates. Therefore the solution is to create an ID2D1StrokeStyle object as the following:

ID2D1StrokeStyle* strokestyle = nullptr;
D2D1_STROKE_STYLE_PROPERTIES strokeprops = D2D1::StrokeStyleProperties();

strokeprops.lineJoin = D2D1_LINE_JOIN_ROUND;

d2dfactory->CreateStrokeStyle(strokeprops, NULL, 0, &strokestyle);

// draw
rendertarget->DrawGeometry(transformedgeometry, blackbrush, 3.0f, strokestyle);

With this solution, the text is rendered as expected (perhaps a little more roundish at the joints).

Asylum
  • 569
  • 4
  • 21
1

I would suspect the reason for that is that default flattening tolerance in D2D does not work well for the purpose of rendering glyph outlines, at small enough sizes. Normally you'd use bitmap rendering for small sizes and outlines for larger ones, according to GetRecommendedRenderingMode(). Do you have same artifacts if you increase font size let's say 10 times?

bunglehead
  • 1,104
  • 1
  • 14
  • 22
  • if I increase the font size, then it looks ok, but the goal would be to make it look good with this font size. Interestingly enough GDI+ can do it. How would you render outlines with bitmap font? – Asylum Mar 31 '21 at 08:14
  • You mean if you feed D2D geometry to GDI+ methods? I guess GDI+ works differently then. What do you mean by bitmap font? If there is no outline for a given glyph, GetGlyphRunOutline will skip it I think, and move on to next one. – bunglehead Mar 31 '21 at 09:24
  • I meant that GDI+ can render outlined text with this font size just perfectly (using GraphicsPath::AddString, Graphics::DrawPath and Graphics::FillPath). Wanted to write 'rasterizer' (not bitmap font, that's totally different), as in if this path geometry method is not suitable for small font sizes, then how do I render outlined text by other means? – Asylum Mar 31 '21 at 10:09
  • I haven't tried myself, if that's really about the tolerance, you could try ID2D1DeviceContext1::CreateFilledGeometryRealization() and play with tolerance value to see if that helps at all. If it does you can then come up with some tolerance estimate based on font size. Another option is to use ID2D1Geometry::Simplify(), that also takes tolerance argument. Default renderer in D2D uses recommended mode, which switch to outline at about ~100.0 emsize. Maybe you found a reason why it's not lower. – bunglehead Mar 31 '21 at 10:58
  • I played around with Simplify() and the tolerance parameter, but the "hairs" are still there. – Asylum Mar 31 '21 at 14:55