2

動作するアルゴリズムを取得できないように見える問題があります。私は何日も努力して、これほど近づいてきましたが、まだこれまでのところです。

3点(p0、p1、p2)で定義される三角形を描きたい。この三角形は、任意の形状、サイズ、および方向にすることができます。三角形も内側に塗りつぶす必要があります。

これが私が試したいくつかのこととそれらが失敗した理由です:

1

  • 三角形に沿って左右に線を引く
    • 三角形に穴があり、位置が変わると角度の付いたサーフェスを横切る線を描くのが面倒なため、平らにならないため、失敗しました。

2

  • エリアを反復処理し、ポイントが三角形に平行な平面と、三角形のエリアをカバーするXY、ZY、およびXZ平面に投影された他の3つの平面を通過するかどうかをテストします。
    • 特定の三角形(非常に近い辺を持つ)の場合、予測できない結果が発生するため、失敗しました。たとえば、ボクセルが何にも接続されていない状態で浮かんでいます。

3

  • 三角形の辺に沿った領域を反復処理し(ラインアルゴリズム)、ポイントが平行平面を通過するかどうかをテストします
    • p0からp1への線の描画は、p1からp0への線と同じではなく、再配置しようとしても役に立たないか、さらに問題が発生するため、失敗しました。これには非対称性が問題です。

これはすべて、ポリゴンと平面を作成することを目的としています。3は私に最も成功をもたらし、正確な三角形を作成しますが、これらを接続しようとすると、すべてがバラバラになり、接続されない、非対称性などの問題が発生します。これを長い間機能させようとすることから抜け出し、助けが必要です。

私のアルゴリズムには、実際には関係のない細かい詳細がたくさんあるので、それらを省略しました。3番目の場合、アルゴリズム自体ではなく、実装に問題がある可能性があります。コードが必要な場合は、理解できるように十分にクリーンアップしてみますが、数分かかります。しかし、私は機能することが知られているアルゴリズムを探しています。ボクセル形状作成アルゴリズムはどこにも見つからないようです。私はすべてをゼロから行ってきました。

編集:

これが3回目の試みです。めちゃくちゃですが、片付けてみました。

// Point3i is a class I made, however the Vector3fs you'll see are from lwjgl

public void drawTriangle (Point3i r0, Point3i r1, Point3i r2)
{
    // Util is a class I made with some useful stuff inside

    // Starting values for iteration

    int sx = (int) Util.min(r0.x, r1.x, r2.x);
    int sy = (int) Util.min(r0.y, r1.y, r2.y);
    int sz = (int) Util.min(r0.z, r1.z, r2.z);

    // Ending values for iteration

    int ex = (int) Util.max(r0.x, r1.x, r2.x);
    int ey = (int) Util.max(r0.y, r1.y, r2.y);
    int ez = (int) Util.max(r0.z, r1.z, r2.z);

    // Side lengths

    float l0 = Util.distance(r0.x, r1.x, r0.y, r1.y, r0.z, r1.z);
    float l1 = Util.distance(r2.x, r1.x, r2.y, r1.y, r2.z, r1.z);
    float l2 = Util.distance(r0.x, r2.x, r0.y, r2.y, r0.z, r2.z);

    // Calculate the normal vector

    Vector3f nn = new Vector3f(r1.x - r0.x, r1.y - r0.y, r1.z - r0.z);
    Vector3f n   = new Vector3f(r2.x - r0.x, r2.y - r0.y, r2.z - r0.z);
    Vector3f.cross(nn, n, n);

    // Determines which direction we increment for

    int iz = n.z >= 0 ? 1 : -1;
    int iy = n.y >= 0 ? 1 : -1;
    int ix = n.x >= 0 ? 1 : -1;

    // Reorganize for the direction of iteration

    if (iz < 0) {
        int tmp = sz;
        sz = ez;
        ez = tmp;
    }
    if (iy < 0) {
        int tmp = sy;
        sy = ey;
        ey = tmp;
    }
    if (ix < 0) {
        int tmp = sx;
        sx = ex;
        ex = tmp;
    }

    // We're we want to iterate over the end vars so we change the value
    // by their incrementors/decrementors

    ex += ix;
    ey += iy;
    ez += iz;

    // Maximum length

    float lmax = Util.max(l0, l1, l2);

    // This is a class I made which manually iterates over a line, I already
    // know that this class is working

    GeneratorLine3d g0, g1, g2;

    // This is a vector for the longest side

    Vector3f v = new Vector3f();

    // make the generators

    if (lmax == l0) {
        v.x = r1.x - r0.x;
        v.y = r1.y - r0.y;
        v.z = r1.z - r0.z;

        g0 = new GeneratorLine3d(r0, r1);
        g1 = new GeneratorLine3d(r0, r2);
        g2 = new GeneratorLine3d(r2, r1);
    }
    else if (lmax == l1) {
        v.x = r1.x - r2.x;
        v.y = r1.y - r2.y;
        v.z = r1.z - r2.z;

        g0 = new GeneratorLine3d(r2, r1);
        g1 = new GeneratorLine3d(r2, r0);
        g2 = new GeneratorLine3d(r0, r1);
    }
    else {
        v.x = r2.x - r0.x;
        v.y = r2.y - r0.y;
        v.z = r2.z - r0.z;

        g0 = new GeneratorLine3d(r0, r2);
        g1 = new GeneratorLine3d(r0, r1);
        g2 = new GeneratorLine3d(r1, r2);
    }

    // Absolute values for the normal

    float anx = Math.abs(n.x);
    float any = Math.abs(n.y);
    float anz = Math.abs(n.z);

    int i, o;
    int si, so;
    int ii, io;
    int ei, eo;

    boolean maxx, maxy, maxz,
    midy, midz, midx,
    minx, miny, minz;

    maxx = maxy = maxz =
    midy = midz = midx =
    minx = miny = minz = false;

    // Absolute values for the longest side vector      

    float rnx = Math.abs(v.x);
    float rny = Math.abs(v.y);
    float rnz = Math.abs(v.z);

    int rmid = Util.max(rnx, rny, rnz);

    if (rmid == rnz) midz = true;
    else if (rmid == rny) midy = true;

    midx = !midz && !midy;

    // Determine the inner and outer loop directions

    if (midz) {
        if (any > anx) 
        {
            maxy = true;
            si = sy;
            ii = iy;
            ei = ey;
        }
        else {
            maxx = true;
            si = sx;
            ii = ix;
            ei = ex;
        }
    }
    else {
        if (anz > anx) {
            maxz = true;
            si = sz;
            ii = iz;
            ei = ez;
        }
        else {
            maxx = true;
            si = sx;
            ii = ix;
            ei = ex;
        }
    }

    if (!midz && !maxz) {
        minz = true;
        so = sz;
        eo = ez;
    }
    else if (!midy && !maxy) {
        miny = true;
        so = sy;
        eo = ey;
    }
    else {
        minx = true;
        so = sx;
        eo = ex;
    }

    // GeneratorLine3d is iterable
    Point3i p1;
    for (Point3i p0 : g0) {
        // Make sure the two 'mid' coordinate correspond for the area inside the triangle

        if (midz)
            do p1 = g1.hasNext() ? g1.next() : g2.next();
            while (p1.z != p0.z);
        else if (midy)
            do p1 = g1.hasNext() ? g1.next() : g2.next();
            while (p1.y != p0.y);
        else
            do p1 = g1.hasNext() ? g1.next() : g2.next();
            while (p1.x != p0.x);

        eo = (minx ? p0.x : miny ? p0.y : p0.z);
        so = (minx ? p1.x : miny ? p1.y : p1.z);
        io = eo - so >= 0 ? 1 : -1;

        for (o = so; o != eo; o += io) {
            for (i = si; i != ei; i += ii) {
                int x = maxx ? i : midx ? p0.x : o;
                int y = maxy ? i : midy ? p0.y : o;
                int z = maxz ? i : midz ? p0.z : o;

                // isPassing tests to see if a point goes past a plane
                // I know it's working, so no code

                // voxels is a member that is an arraylist of Point3i

                if (isPassing(x, y, z, r0, n.x, n.y, n.z)) {
                    voxels.add(new Point3i(x, y, z));
                    break;
                }
            }
        }
    }
}
4

2 に答える 2

1

Besenham のライン アルゴリズムのようなものを使用できますが、3 次元に拡張されます。そこから得たい 2 つの主なアイデアは次のとおりです。

  • 最初の線を回転させて、傾きが急すぎないようにします。
  • 任意の x 値について、理想的な y 値に最も近い整数値を見つけます。

Bresenham のアルゴリズムが最初のローテーションを実行することでギャップを防ぐように、最初の 2 回のローテーションを実行することで穴を回避します。

  1. 三角形がある平面を表す法線ベクトルと点を取得します。ヒント: (p0 から p1 への直線) と (p0 から p2 への直線) の外積をベクトルに使用し、任意のコーナー ポイントをポイントに使用します。
  2. 穴を避けるために、平面を十分に急勾配にしないようにする必要があります。次の条件を満たす必要があります。

    • -1 >= norm.x / norm.y >= 1
    • -1 >= norm.z / norm.y >= 1

    これらの条件が満たされるまで、x 軸を中心に 90 度、z 軸を中心に 90 度、法線ベクトルと初期点を回転させます。最小の回転数でこれを行う方法はわかりませんが、どの平面でもこれらの条件を満たすことができると確信しています。

  3. 回転した三角形が現在置かれている平面を表す関数 f(x,z) を作成します。X 値と Z 値の任意のペアの Y 値を返す必要があります。
  4. 三角形を XZ 平面に投影し (つまり、すべての y 値を 0 に設定)、お気に入りの 2D 三角形描画アルゴリズムを使用して、x 座標と z 座標のコレクションを取得します。
  5. ステップ 4 の各ピクセル値について、x 値と z 値をステップ 3 の関数 f(x,z) に渡します。結果を最も近い整数に丸め、x、y、z 値をボクセルとしてどこかに保存します。
  6. 手順 2 で回転を実行した場合は、ボクセル コレクションに対して逆の順序で回転を実行します。
于 2012-06-11T17:42:15.310 に答える
0

三角形/ボクセルの交差をチェックする関数から始めます。これで、ボリュームをスキャンして、三角形と交差するボクセルを見つけることができます。これらは、関心のあるボクセルです。これはお粗末なアルゴリズムですが、他の試みに対する回帰テストでもあります。このテストは、SAT (分離軸定理) を使用して簡単に実装でき、三角形を縮退ボリューム (1 つの面、3 つのエッジ) と見なし、ボクセルの対称性 (3 つの面法線のみ) を考慮します。

私は octtrees を使用しているので、大きなボクセルに対して三角形をテストし、それが交差する 8 つの子 octants を特定する方法を好んで使用しています。次に、必要なレベルの細分化が達成されるまで、交差する子に対して再帰を使用します。ヒント: 三角形と交差できる子は最大 6 個で、多くの場合、それより少なくなります。これは注意が必要ですが、最初の方法と同じ結果が得られますが、はるかに高速です。

3D でのラスタライズはおそらく最速ですが、すべてのケースで穴がないことを保証するのはさらに困難です。ここでも、最初の方法を使用して比較します。

于 2012-06-11T18:03:25.200 に答える