編集:具体的な解決策と私の他の答えをご覧ください。
私は実際に修士論文のために1年以上前にこの正確な問題を解決しました。バルブペーパーでは、2つの距離フィールドとこれを実現することができることを示しています。これは、凸状のコーナーが1つしかない限り機能します。凹型コーナーの場合は、OR演算も必要です。この男は、実際には、4つのテクスチャチャネルを使用して2つの操作を切り替えるための不明瞭なシステムを開発しました。
しかし、状況に応じてANDとORの両方を容易にすることができるはるかに単純な操作があり、これが私の論文の主要な考えです:3の中央値。したがって、基本的には、完全に交換可能な正確に3つのチャネル(RGBに最適)を使用し、中央値演算を使用してそれらを結合します(3つから中央の値を選択します)。
アンチエイリアシングに対応するために、ブール値だけではなく、浮動小数点値、およびAND演算が最小になり、ORが2つの値の最大値になります。3の中央値は実際に両方を行うことができます:a < bの場合、(a、a、b)の場合、中央値は最小であり、(a、b、b)の場合、最大値です。
レンダリングプロセスは依然として非常に簡単です。アンチエイリアスを含むフラグメントシェーダー全体は、次のようになります。
int main() {
// Bilinear sampling of the distance field
vec3 s = texture2D(sdf, p).rgb;
// Acquire the signed distance
float d = median(s.r, s.g, s.b) - 0.5;
// Weight between inside and outside (anti-aliasing)
float w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
// Combining the background and foreground color
gl_FragColor = mix(outsideColor, insideColor, w);
}
したがって、元の方法との唯一の違いは、テクスチャをサンプリングした直後に中央値を計算することです。ただし、中央値関数を実装する必要があります。これは、わずか4 min / max操作で実行できます。
もちろん、問題は、このような3チャンネルの距離フィールドをどのように構築すればよいのかということです。そして、これはトリッキーな部分です。私が最初に取った最も明白なアプローチは、入力形状/グリフを3つのコンポーネントに分解し、それぞれから従来の距離フィールドを生成することでした。この分解のルールはそれほど複雑ではありません。まず、3つのチャネルのうち少なくとも2つがオンになっているエリアが内側です。次に、これをRGBカラーチャネルと考える場合、凸状の角は2次色で作成する必要があり、その2つの主要コンポーネントは外側に向かって続きます。凹角は逆です。2つの2次色は共通の1次色を囲み、両方のエッジが内側に続く部分の間のくさびは白です。また、アーティファクトを回避するために2つのプライマリカラーまたは2つのセカンダリカラーが接触する場合は、いくつかのパディングが必要であることがわかりました(たとえば、「N」
次の図は、私の論文のプログラムによって生成された分解の例です。
ただし、このアプローチにはいくつかの欠点があります。その1つは、アウトラインや影などの特殊効果が正しく機能しなくなることです。幸運にも、距離フィールドを直接生成し、すべてのグラフィック効果をサポートする、よりエレガントな2番目の方法も思いつきました。私の論文にも含まれているので、1年以上も経っています。現在、この2番目の手法を詳細に説明する論文を執筆しているため、これ以上詳細を説明するつもりはありませんが、完了したらすぐにここに投稿します。
とにかく、ここに品質の違いの例があります。テクスチャ解像度は各画像で同じですが、左のものは通常のテクスチャを使用し、中央のものは通常の距離フィールドを使用し、右のものは私の3チャンネル距離フィールドを使用します。パフォーマンスのオーバーヘッドは、RGBテクスチャのサンプリングとモノクロテクスチャのサンプリングの違いのみです。