複雑なポリゴンラスタライズアルゴリズム

gboxのグラフィックライブラリプロジェクトは1年以上維持されていませんが、最近は本当に十分な時間がありません。

今年の焦点は、少なくともアーキテクチャと主要な機能(パッケージの依存関係管理)に関してxmakeを完全に正しく実装し、完全に実装することです。後の期間は、メンテナンスとプラグイン機能の拡張が散在しています。

今後もtboxの小規模なアップデートを行い、来年前半にモジュールを少しリファクタリングした後、gboxの再構築に注力していきます。これは私がずっとやりたかったプロジェクトです。また、私のお気に入りのプロジェクト。

ですから、開発を遅らせるだけでなく、より正確にして最善を尽くしたいと思います。

さて、トピックに戻りましょう。gboxはまだ開発の初期段階にあり、実際のプロジェクトでは使用できませんが、その中のアルゴリズムのいくつかは、参照と学習に非常に役立ちます。

過去2日間は何の関係もなく、共有しています。興味のある学生がいる場合は、ソースコードmonotone.cを直接読むことができます。

結局のところ、このアルゴリズムを完全に取得して実装するのに1年かかりました。

なぜそんなに時間がかかったのか、多分私は愚かすぎる。ふふ。もちろん、仕事の理由もあります。

この複雑なポリゴンラスタライズアルゴリズムの研究と実装の背景について簡単に説明します。

私のgbox現在2つのレンダリングデバイスがあります。直接純粋なレンダリングアルゴリズムです。アルゴリズムのコアはポリゴンフィルアルゴリズムをスキャンすることです。これは非常に一般的で、非常に成熟していて、非常に効率
高いと考えられていますが、他のセットではopenglに基づいていますesレンダリングデバイス(高速レンダリングにGPUを使用できるようにするため)、複雑なポリゴンをレンダリングすると、次の問題が発生します。opengl不支持复杂多边形的填充

後で、私は多くの方法を考えました、そして私もグーグルに行きました、そしてそれがOpenGLテンプレートを通して達成されることができるとわかりました、そしてそれから私は書き始めました。

執筆の途中で全体的な効果が出ました。できたと思いましたが、克服が難しいボトルネックに遭遇しました。効率が低すぎました。この方法で虎の頭をレンダリングすると、フレームレートはわずか15になります。 fps

純粋なアルゴリズムを使用した実装よりも遅いのですが、後でなぜこんなに遅いのかを考えました。理由の1つは、テンプレートが本当に遅いことでした。

2つ目の理由は、ユニバーサルレンダリングインターフェイスを実装し、さまざまな塗りつぶしルールとトリミングルールをサポートしたいということです。これらの複雑さにより、テンプレートベースのアプローチ全体を最適化するのも簡単ではありません。

このように半年間投げた後、私はついにテンプレートをまったく使用せずにgbox全体をリファクタリングし、別の方法を採用することにしました。

まず、複雑なポリゴンは、さまざまな塗りつぶしルールとクリッピングに従って上位レイヤーで前処理されます。コアアルゴリズムは次のとおりです。对复杂多边形进行三角化分割,并且合并成凸多边形
次に、高速レンダリングのためにOpenGLに送信します。

では、問題は、ポリゴンを効率的に分割でき、さまざまな塗りつぶしルールをサポートする必要がある場合はどうなるかということです。

グーグルを続ける、最終的にラスターコード内で見つかったlibtess2アルゴリズムは完全に行うことができますが、コードで直接使用することはできません。
別の理由の1つは、実装の内部にあることです。効率はそれほど高くありません。非常に高く、私が達成したいことは彼よりも効率的で安定しています。

次に、最初にその実装ロジックを確認してから、内部のアルゴリズム実装を改善および最適化する必要があります。

コードはあまりありませんが、読むのにさらに半年かかり、最後に次々と書くのに半年かかり、ようやく完成しました。

最終的な効果はまだ良好です。少なくともopenglレンダリングタイガーヘッドを搭載した私のMacProでは、フレームレートは60fpsに達する可能性があります。

もちろん、そこにはたくさんの問題があるはずです。そうしないと、最近修正する時間が本当にありません。脇に置いて後で最適化するしかありません。

最初に公開し、三角測量後の効果:

test_triangulation1
test_triangulation2
test_triangulation3

そして、虎の頭の効果を置きます:

draw_tiger

次に、セグメンテーションアルゴリズムについて簡単に説明します。

gboxに実装されているアルゴリズムとlibtess2のアルゴリズムの違いと改善点は次のとおりです。

  • 全体的なスキャンラインの方向が垂直スキャンから水平スキャンに変更されました。これは、画像スキャンシートロジックとより一致しており、コード処理がより便利になります。
  • 3D頂点座標投影プロセスを削除しました。これは、2Dポリゴンのみを処理するため、libtess2よりも高速になります。
  • より多くの交差点を処理し、交差点誤差の計算がある場所をより多く最適化して、アルゴリズムがより安定してより正確になるようにします
  • 浮動小数点および固定小数点スイッチングの全体的なサポートにより、効率と精度の観点から自分で重量を量り、調整することができます
  • 独自のアルゴリズムを使用して、より高い精度とより優れた安定性でアクティブエッジ比較を実現します
  • 三角形メッシュから凸多角形にマージするアルゴリズムを最適化しました。これはより効率的です。
  • エリアトラバーサルごとに、不要な固定小数点カウントプロセスが削除されるため、効率が大幅に向上します。

アルゴリズム全体には、合計4つの段階があります。

  1. 元の複雑なポリゴンからDCELメッシュネットワークを構築します(クアッドエッジと同様のDCEL二重接続エッジリンクリスト、簡略化されたバージョンと同等)。
  2. ポリゴンが凹面または複雑な場合は、最初に単調なポリゴン領域に分割します(メッシュ構造のメンテナンス)
  3. メッシュベースの単調ポリゴンの高速三角測量
  4. 三角形分割された領域を凸多角形にマージします

ラスタライズアルゴリズムの実装には、次の7つの段階があります。

  1. メッシュネットワークを簡素化し、いくつかの劣化した状況に事前に対処します(たとえば、サブ領域が点や線などに縮退します)。
  2. 頂点イベントのリストを作成し、それを並べ替えます(最小のヒープの優先度に基づいて)。
  3. アクティブなエッジ領域のリストを作成して並べ替えます(ローカル領域の挿入ソートを使用します。ほとんどの場合、O(n)であり、量はそれほど多くありません)。
  4. Bentley-Ottmanスキャンアルゴリズムを使用して、イベントキューからすべての頂点イベントをスキャンし、交差値と巻線値を計算します(ルール計算の入力に使用されます)
  5. 交点がメッシュネットワークのトポロジを変更した場合、またはアクティブエッジリストが変更された場合は、メッシュの整合性を修復する必要があります
  6. mesh face劣化に対処するときは、それに対処する必要もあります
  7. 単調な領域left faceを「内部」としてマークします。これは、最後に取得する必要がある出力領域です。

アルゴリズムの詳細を知りたい場合は、libtess2 /alg_outline.mdを参照してください。

ソースコードからのラスタライズインターフェイスの使用例:gbox / gl / render.c

アルゴリズムの実装の詳細については、私の実装を参照してください:monotone.c

    static tb_void_t gb_gl_render_fill_convex(gb_point_ref_t points, tb_uint16_t count, tb_cpointer_t priv)
    {
        // check
        tb_assert(priv && points && count);

        // apply it
        gb_gl_render_apply_vertices((gb_gl_device_ref_t)priv, points);

#ifndef GB_GL_TESSELLATOR_TEST_ENABLE
        // draw it
        gb_glDrawArrays(GB_GL_TRIANGLE_FAN, 0, (gb_GLint_t)count);
#else
        // the device 
        gb_gl_device_ref_t device = (gb_gl_device_ref_t)priv;

        // make crc32
        tb_uint32_t crc32 = 0xffffffff ^ tb_crc_encode(TB_CRC_MODE_32_IEEE_LE, 0xffffffff, (tb_byte_t const*)points, count * sizeof(gb_point_t));

        // make color
        gb_color_t color;
        color.r = (tb_byte_t)crc32;
        color.g = (tb_byte_t)(crc32 >> 8);
        color.b = (tb_byte_t)(crc32 >> 16);
        color.a = 128;

        // enable blend
        gb_glEnable(GB_GL_BLEND);
        gb_glBlendFunc(GB_GL_SRC_ALPHA, GB_GL_ONE_MINUS_SRC_ALPHA);

        // apply color
        if (device->version >= 0x20) gb_glVertexAttrib4f(gb_gl_program_location(device->program, GB_GL_PROGRAM_LOCATION_COLORS), (gb_GLfloat_t)color.r / 0xff, (gb_GLfloat_t)color.g / 0xff, (gb_GLfloat_t)color.b / 0xff, (gb_GLfloat_t)color.a / 0xff);
        else gb_glColor4f((gb_GLfloat_t)color.r / 0xff, (gb_GLfloat_t)color.g / 0xff, (gb_GLfloat_t)color.b / 0xff, (gb_GLfloat_t)color.a / 0xff);

        // draw the edges of the filled contour
        gb_glDrawArrays(GB_GL_TRIANGLE_FAN, 0, (gb_GLint_t)count);

        // disable blend
        gb_glEnable(GB_GL_BLEND);
#endif
    }
    static tb_void_t gb_gl_render_fill_polygon(gb_gl_device_ref_t device, gb_polygon_ref_t polygon, gb_rect_ref_t bounds, tb_size_t rule)
    {
        // check
        tb_assert(device && device->tessellator);

#ifdef GB_GL_TESSELLATOR_TEST_ENABLE
        // set mode
        gb_tessellator_mode_set(device->tessellator, GB_TESSELLATOR_MODE_TRIANGULATION);
//      gb_tessellator_mode_set(device->tessellator, GB_TESSELLATOR_MODE_MONOTONE);
#endif

        // set rule
        gb_tessellator_rule_set(device->tessellator, rule);

        // set func
        gb_tessellator_func_set(device->tessellator, gb_gl_render_fill_convex, device);

        // done tessellator
        gb_tessellator_done(device->tessellator, polygon, bounds);
    }

個人ホームページ:TBOOXオープンソースプロジェクト
元のソース:http//tboox.org/cn/2016/07/21/tessellate-polygon-algorithm/

おすすめ

転載: blog.csdn.net/waruqi/article/details/53201513