MSDFフォントを使った文字効果
もじさん  2025/02/01(Sat) 15:19
MSDFフォントの描画で以下2つの効果をかけることは可能でしょうか
1. 輪郭の二重化(白線+黒線など)
2. カラーグラデーション

文字に輪郭を付けるサンプルと、グラデーションのあるテキストのサンプルを確認しましたが、
MSDFフォントでどのように実現すればよいか分かりませんでした。
使用バージョンはv0.6.15です。宜しくお願いします。
記事編集
Reputeless  2025/02/04(Tue) 12:08
@ 輪郭の二重化

# include <Siv3D.hpp>

void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

const Font font{ FontMethod::MSDF, 48, Typeface::Bold };

while (System::Update())
{
font(U"Hello, Siv3D!")
.draw(TextStyle::Outline(0.2, 0.0, ColorF{ 1.0 }), 80, Vec2{ 40, 40 }, ColorF{ 0.2, 0.4, 1.0 });

font(U"Hello, Siv3D!")
.draw(TextStyle::Outline(0.0, 0.2, ColorF{ 0.0 }), 80, Vec2{ 40, 40 }, ColorF{ 0.0, 0.0 });
}
}




A カラーグラデーション

# include <Siv3D.hpp>

BlendState MakeBlendState()
{
BlendState blendState = BlendState::Default2D;
blendState.srcAlpha = Blend::SrcAlpha;
blendState.dstAlpha = Blend::DestAlpha;
blendState.opAlpha = BlendOp::Max;
return blendState;
}

void RenderText(const Font& font, const RenderTexture& renderTexture, const double fontSize, const StringView text)
{
// レンダーターゲットを renderTexture に変更する
const ScopedRenderTarget2D target{ renderTexture.clear(ColorF{ 1.0, 0.0 }) };

// 描画された最大のアルファ成分を保持するブレンドステート
const ScopedRenderStates2D blend{ MakeBlendState() };

// テキストを描画する
font(text).draw(fontSize, Vec2{ 0, 0 });
}

void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

const Font font{ FontMethod::MSDF, 48, Typeface::Bold };

const RenderTexture renderTexture{ Size{ 800, 120 } };

RenderText(font, renderTexture, 90, U"Hello, Siv3D!");

while (System::Update())
{
renderTexture.draw(Arg::top(0.2, 0.8, 0.4), Arg::bottom(0.2, 0.4, 0.8));

Rect{ renderTexture.size() }.drawFrame(1, 0, Palette::Black);
}
}
編集
もじさん  2025/02/04(Tue) 22:00
ご回答ありがとうございます。
両方ともうまくいきました。

@とAを組み合わせたい場合は、
まずAの描画を行った上で、@の描画をインナー、アウター共にフォントのアルファをゼロにして
描画する形になりますでしょうか。

また、Aでテキストが可変の場合、
テキストのサイズに応じてRenderTextureのサイズも見直したいのですが、
W100 | Inefficient Asset Creationのワーニングがでてしまいました。
処理を重くせずに回避する方法はありますでしょうか。

宜しくお願い致します。
編集
Reputeless  2025/02/05(Wed) 01:15
> Aの描画を行った上で、@の描画をインナー、アウター共にフォントのアルファをゼロにして描画する形

そうなります。


> RenderTexture

RenderTexture の再作成を可能な限り減らせる実装を考えてください。

例えば、あらかじめ大きな RenderTexture を作成し、renderTexture(x, y, w, h) で切り取った範囲をグラデーション描画することができます。
編集
もじさん  2025/02/05(Wed) 21:53
ご回答ありがとうございます。

もう一点、ご教示いただきたいのですが、
Aのカラーグラデーションのサンプルコードで、Main関数を以下の様に変更し、
2回描画させると、2回目の描画が残像が残った形になり、うまくいきません。

これを回避するには、RenderTextureをもうひとつ用意する必要がありますでしょうか。
宜しくお願い致します。

void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });

const Font font{ FontMethod::MSDF, 48, Typeface::Bold };

const RenderTexture renderTexture{ Size{ 800, 120 } };

while (System::Update())
{
RenderText(font, renderTexture, 90, U"Hello, Siv3D!");
renderTexture.draw(Arg::top(0.2, 0.8, 0.4), Arg::bottom(0.2, 0.4, 0.8));

RenderText(font, renderTexture, 100, U"Hello, Siv3D!");
renderTexture.draw(0, 200, Arg::top(0.2, 0.8, 0.4), Arg::bottom(0.2, 0.4, 0.8));
}
}
編集
Reputeless  2025/02/05(Wed) 23:09
clear() は即時操作な一方、draw() は単なる操作の予約で、実際の描画は `System::Update()` 内で実行されることから、このようなことが起こります。
間に `Graphics2D::Flush();` を挟んで、予約された描画を実行することで解決できます。
編集
もじさん  2025/02/06(Thu) 20:01
Graphics2D::Flush()で解決しました。
ありがとうございました。
編集
件名
Re: MSDFフォントを使った文字効果
名前
コメント
画像添付


投稿修正キー (投稿を修正する時に使います)
画像認証 (右画像の数字を入力) 投稿キー

- WEB PATIO -