web-dev-qa-db-ja.com

球の頂点を生成する

DirectXモバイル照明サンプルでは、​​円柱は次の方法で生成されます。

for( DWORD i=0; i<50; i++ )
            {
                FLOAT theta = (2*D3DMX_PI*i)/(50-1);
                pVertices[2*i+0].position = D3DMXVECTOR3( (float)sin(theta),-1.0f, (float)cos(theta) );
                pVertices[2*i+0].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
                pVertices[2*i+1].position = D3DMXVECTOR3( (float)sin(theta), 1.0f, (float)cos(theta) );
                pVertices[2*i+1].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
            }

DirectX Mobileで球の頂点を(三角ストリップなどとして)生成する同様の方法はありますか? (AFAIKにはD3DMXCreateSphereメソッドはありません)


最終的な解決策。クォータニオンのすべての支援に感謝します。

void CreateSphere()
{
    const int iFactor = 20;
    int iPos = 0;

    arr_Vertices = new CUSTOMVERTEX[ui_VCount];
    ui_ShapeCount = iFactor *iFactor * 2; // use when rendering

    float arrV[iFactor* iFactor][3];

    for (DWORD j= 0; j < iFactor; j ++)
    {
        FLOAT theta = (D3DMX_PI*j)/(iFactor);

        for( DWORD i=0; i<iFactor; i++ )
        {
            iPos = j*iFactor+i;
            FLOAT phi = (2*D3DMX_PI*i)/(iFactor);
            arrV[iPos][0] = (float)(sin(theta)*cos(phi));
            arrV[iPos][1] = (float)(sin(theta)*sin(phi));
            arrV[iPos][2] = (float)(cos(theta));

            /*std::cout << "[" << j <<"][" << i << "] = " << arrV[iPos][0]  
                << "," << arrV[iPos][1] << "," << arrV[iPos][2] <<std::endl;*/
        }
    }

    int iNext = 0;

    for (DWORD j= 0; j < iFactor; j ++)
    { 

        for( DWORD i=0; i<iFactor; i++ )
        {
            if (i == iFactor - 1)
                iNext = 0;
            else iNext = i +1;

            iPos = (j*iFactor*6)+(i*6);
            arr_Vertices[iPos].position = D3DMXVECTOR3( arrV[j*iFactor+i][0], arrV[j*iFactor+i][1], arrV[j*iFactor+i][2]);
            arr_Vertices[iPos + 1].position = D3DMXVECTOR3( arrV[j*iFactor+iNext][0], arrV[j*iFactor+iNext][1], arrV[j*iFactor+iNext][2]);


            if (j != iFactor -1)
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+i][0], arrV[((j+1)*iFactor)+i][1], arrV[((j+1)*iFactor)+i][2]);
            else
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( 0, 0, -1); //Create a pseudo triangle fan for the last set of triangles

            arr_Vertices[iPos].normal = D3DMXVECTOR3( arr_Vertices[iPos].position.x, arr_Vertices[iPos].position.y, arr_Vertices[iPos].position.z);
            arr_Vertices[iPos + 1].normal = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);
            arr_Vertices[iPos + 2].normal = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);

            arr_Vertices[iPos + 3].position = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);
            arr_Vertices[iPos + 4].position = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);

            if (j != iFactor - 1)
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+iNext][0], arrV[((j+1)*iFactor)+iNext][1], arrV[((j+1)*iFactor)+iNext][2]);
            else
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( 0,0,-1);

            arr_Vertices[iPos + 3].normal = D3DMXVECTOR3( arr_Vertices[iPos+3].position.x, arr_Vertices[iPos+3].position.y, arr_Vertices[iPos+3].position.z);
            arr_Vertices[iPos + 4].normal = D3DMXVECTOR3( arr_Vertices[iPos+4].position.x, arr_Vertices[iPos+4].position.y, arr_Vertices[iPos+4].position.z);
            arr_Vertices[iPos + 5].normal = D3DMXVECTOR3( arr_Vertices[iPos+5].position.x, arr_Vertices[iPos+5].position.y, arr_Vertices[iPos+5].position.z);

            //std::cout << "[" << iPos <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos].position.y <<
            //  "," << arr_Vertices[iPos].position.z <<std::endl;

            //std::cout << "[" << iPos + 1 <<"] = " << arr_Vertices[iPos + 1].position.x << 
            //  "," << arr_Vertices[iPos+ 1].position.y <<
            //  "," << arr_Vertices[iPos+ 1].position.z <<std::endl;

            //std::cout << "[" << iPos + 2 <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos + 2].position.y <<
            //  "," << arr_Vertices[iPos + 2].position.z <<std::endl;
        }
    }
}

わずかな調整で使用できるはずです。これによりTRIANGLELISTが作成されますが、三角ストリップのセットを出力するように変更できます。

14
Gayan

それについての基本的な考え方:

連続三角ストリップを使用しない最初の方法...

久しぶりなので間違えるかも….

パラメトリックに定義された単位円:

Where 0 =< theta < 2pi 
x = sin(theta);
y = cos(theta);

単一の円を定義できるようになったので、x、y平面上の同心円を想像してください。ここで、最も内側の円を上げることを想像してください。上げると、スリンキーのように次のリングが引き上げられます...このビジュアルは半球に対してのみ機能します。

したがって、同心リングから球の形状を生成するフォームは、もちろん、リングに直交する別の円、(z、y)平面です...もちろん、リングのオフセットを見つけることだけに関心があります( (x、y)平面からオフセットする必要がある高さまたは低さ。

オフセットが必要なだけなので、必要なのは半円だけです...さらに、極は1点だけになります。各リング間のポールとストリップに三角形のファンを使用します。

このメンタルエクササイズの後、 http://en.wikipedia.org/wiki/Sphere を参照し、「半径rの球上の点は、を介してパラメーター化できます」を検索すると、パラメトリックフォームが表示されます。その行の後。

法線は非常に簡単です。球は常に(0,0,0)の周りに構築する必要があり、球は常に半径1で構築する必要があります(したがって、単純に目的のサイズにスケーリングできます)。次に、円の各頂点表面は法線と同じです。


上記の方法では、2つの三角ファンと一連の三角ストリップを使用します...頂点が均等に分布し、1つの三角ストリップで描画できる球を生成する別の方法ですが、現時点ではコーディングに夢中ですこれには次のアイデアが含まれます。

原点を中心とする四面体を想像してください(点は0,0,0から1単位です)。これは球のかなり哀れな表現ですが、近似値です。ここで、4つの面のそれぞれに中点を見つけ、球の表面に来るまでその点を押し出すと想像してください。次に、それらの面の中点を見つけて、球の表面に押し出します...

tetrahdralSphere(int recursions){}

中点を見つけるのは非常に簡単で、x、y、zコンポーネントのそれぞれの平均です。次に、球は単位球であるため、それらを表面に移動するのは、この新しいベクトルを正規化するのと同じくらい簡単です。


方法1は、経度と緯度の線に見える点分布を生成し、不均一な分布を生成します(四角形とワイヤーフレームを使用すると、地球のように見えます)。実装は非常に簡単です。 2番目の方法では再帰が必要なため、少し難しくなりますが、より均一に見えます。非常に複雑になって頭を痛めたい場合は、nポイントを分散してから、ポイント間の反発力をシミュレートして、ポイントを離し、サーフェス全体で正規化します。これを効果的に機能させるために対処する必要のあるあらゆる種類の頭痛の種がありますが、ポイントがかなり均一に分散され、頂点の数を制御でき、モデリングツールに必要なものを理解し始めることができます。モデルを表す最小のジオメトリを見つけます。


最初の方法で行きます。 (0,0,1)に点を描き、最初の同心リングが必要です(簡単にするために、各リングには同じ数の点があります)。

リングごとに10ポイントを描画しましょう...したがって、ファイは2pi/10の増分でステップし、10個の同心リングを描画します

そして、10個のリングと2個の極を描画して、シータがpi/12の増分で増加するようにします。

//this psudo code places the points
//NOT TESTED
deltaTheta = pi/12;
deltaPhi = 2pi/10;
drawVertex(0,0,1) //north pole end cap
for(int ring; ring < 10; ring++){ //move to a new z - offset 
  theta += deltaTheta;
  for(int point; point < 10; point++){ // draw a ring
    phi += deltaPhi;
    x = sin(theta) * cos(phi)
    y = sin(theta) * sin(phi)
    z = cos(theta)
    drawVertex(x,y,z)
  }
}
drawVertex(0, 0, -1) //south pole end cap
11
Quaternion

単位球を三角測量する通常の方法は、 四面体 または 二十面体 を作成することです。

  • 精度が十分な場合は停止します
  • それ以外の場合、既存の顔ごとに:
  • 各エッジの中点に頂点を追加し、単位球上にあるように正規化します。
  • 面を4つの新しい面に置き換えます。面の1つには、コーナーとして3つの新しい中点があります(紙に描くと、他の3つの面が明らかになります)
  • ループ。

エッジの中点で頂点が重複しないようにするには、再利用するために既存の頂点を追跡する必要があります。

5
Alexandre C.

この質問 への回答として、私の投稿でかなり詳細に説明しています。

2
Goz