3

ポイントのリストで定義されたパスに沿ってチューブを描きたいです。

私が考えたのは、基本的に各ポイントの周りに円を描き、GL_QUAD_STRIPを使用して円(またはむしろ円上のポイント)を接続できるということです。

したがって、円上にポイントを作成するための私のコードは次のようになります。

        point_of_circle[0] = pathVertices[i][0] + TUBE_RADIUS * cos(j/TUBE_SEGMENTS * 2*M_PI));
        point_of_circle[1] = pathVertices[i][1] + TUBE_RADIUS * sin(j/TUBE_SEGMENTS * 2*M_PI));
        point_of_circle[2] = pathVertices[i][2];

ここiで、はパス頂点のインデックス(つまり、チューブを描画する元のポイントの1つ)であり、jは作成中の円の現在のポイントのインデックスです(0からTUBE_SEGMENTS)。

さて、問題は、この方法で円を作成すると、それらは常に同じ方向に向けられることです(円はすべて互いに「平行」でありpoint_of_circle[2] = pathVertices[i][2]、いつものように見えます)。構造は適切なチューブのようには見えません。

私ができることは、描画しているパスに接するベクトルを計算することだと思いました。次に、計算された接線に応じて、円を正しい方向に向ける必要があります。

たとえば、計算された接線がである場合0,0,1、コードはそのままである必要があります。ただし、接線を他の方法で計算する場合は、円を回転させる必要があります。

たとえば、計算された接線がである場合0,1,0、y座標は円全体で同じである必要があり、z軸に沿って見ている場合は、円の水平セグメントのみが表示されます。

接線が1,0,0であった場合、z軸に沿って見ると、円の垂直セグメントが表示されます。

計算された接線に応じて円を適切に作成するコードを作成するにはどうすればよいですか?私の説明が十分に明確であることを願っています。私はOpenGLとほとんどの3D数学の初心者です。

4

3 に答える 3

2

車輪を再発明する必要がない場合は、常にGLE チューブおよび押出ライブラリがあります。

于 2012-06-25T23:27:45.883 に答える
1

私は似たようなものを実装しており、いくつかの提案を提供できます。

P_0、P1 などをパス上のポイントとします。チューブはセグメントで構成されています S_i = (P_i, Pi+1)

あなたのアプローチは正しいです-P_iの周りに円を生成し、それらを各セグメントのクワッドストリップとして結合できます。セグメント S_0 から S_N-2 では、それぞれ 1 つの円があり、最後のセグメント S_N-1 では、2 つの円が生成されます。

セグメント S_i = (P_i, P_i+1) の円を生成するには、セグメント方向 D = P_i+1 - P_i を計算します。次に、Normal = D で平面上に円を生成する必要があります。これにはさまざまな方法があります。XY 平面に事前に計算された円の点があり、その点を変換できる場合があります。

ここでの主な問題は、セグメントからセグメントに移動すると、セグメント ベクトルが変化すると円の「原点」ポイントが一致しないため、チューブがねじれ始める可能性があることです。これは、チューブにテクスチャを適用する場合に特に重要です。これに取り組む 1 つのアプローチは、「上側」の基準に基づいて、生成された円の最初のポイントを選択することです。3D のチューブを想像してみてください。視覚的には、チューブが常にチューブの上にくるように、チューブに 3D 線を描くのは簡単です。この「上面」ベクトルは、チューブ セグメントの方向に依存し、チューブの垂直断面では定義されません。非垂直断面の場合、次の式で与えられます。

T=DX(ゼクスド)

X は外積、Z は上方向です。

私の経験に基づいて、これを正しく行うのは難しいです。残念ながら、コードを共有することはできません。幸運を。

于 2012-06-26T06:46:24.093 に答える
0

タンジェントを見つけたら、次のように回転クォートを取得できます。(参照: Ogre3D Vector3.cpp)

    public static Quaternion getRotationTo(Vector3 src, Vector3 dest)
    {
        Quaternion q = new Quaternion();

        src.Normalize();
        dest.Normalize();

        double d = Vector3.Dot(src, dest);

        if (d >= 1.0f)
        {
            return Quaternion.Identity;
        }

        if (d < (1e-6f - 1.0f))
        {
            //                   // Generate an axis
            //                   Vector3 axis = Vector3::UNIT_X.crossProduct(*this);
            //                   if (axis.isZeroLength()) // pick another if colinear
            //                       axis = Vector3::UNIT_Y.crossProduct(*this);
            //                   axis.normalise();
            //                   q.FromAngleAxis(Radian(Math::PI), axis);

            // Generate an axis
            Vector3 axis = Vector3.Cross(Vector3.UnitX, src);

            if (axis.Length() == 0.0f)
            {
                axis = Vector3.Cross(Vector3.UnitY, src);
            }

            axis.Normalize();

            q = Quaternion.CreateFromAxisAngle(axis, MathHelper.ToRadians(180));
        }
        else
        {
            //               Real s = Math::Sqrt( (1+d)*2 );
            //               Real invs = 1 / s;

            //               Vector3 c = v0.crossProduct(v1);

            //               q.x = c.x * invs;
            //               q.y = c.y * invs;
            //               q.z = c.z * invs;
            //               q.w = s * 0.5;
            //               q.normalise();

            Double s = Math.Sqrt((1 + d) * 2);
            Double invs = 1 / s;

            Vector3 c = Vector3.Cross(src, dest);

            q.X = (float)(c.X * invs);
            q.Y = (float)(c.Y * invs);
            q.Z = (float)(c.Z * invs);
            q.W = (float)(s * 0.5);
            q.Normalize();

        }


        return q;
    }
于 2012-06-26T06:10:57.187 に答える