« 球の描画1 | メイン | カメラの回転1 »

2011年06月17日

3D プログラミング:: 球の描画2

    

球の描画1に続き球の描画。
正二十面体を使う方法。
各頂点座標は以下で求める。

a = 1.0f / sqrt(5.0f) = 0.447213595
b = (1.0f - a) / 2.0f = 0.276393202
c = (1.0f + a) / 2.0f = 0.723606797
d = sqrt(b) = 0.525731112
e = sqrt(c) = 0.850650808

頂点座標は以下のようになる。
(0,1,0)(0,a,2a)(e,a,b)(d,a,-c)(-d,a,-c)(-e,a,b)(d,-a,c)(e,-a,-b)(0,-a,-2a)(-e,-a,-b)(-d,-a,c)(0,-1,0)

参考ページ
正二十面体(正20面体、Icosahedron)の頂点情報

これがわかれば二十面体を描画するのは簡単。
以下、前回に続き Java のソース。

public void draw( Sphere shape, GL2 gl ) {
    final float IA = 0.447213595f;
    final float IB = 0.276393202f;
    final float IC = 0.723606797f;
    final float ID = 0.525731112f;
    final float IE = 0.850650808f;
    final float VTX[][] = {
        { 0.0f, 1.0f,    0.0f },    // 0
        { 0.0f,   IA, 2.0f*IA },
        {   IE,   IA,      IB },
        {   ID,   IA,     -IC },
        {  -ID,   IA,     -IC },
        {  -IE,   IA,      IB },    // 5
        {   ID,  -IA,      IC },    // 6
        {   IE,  -IA,     -IB },
        { 0.0f,  -IA,-2.0f*IA },
        {  -IE,  -IA,     -IB },
        {  -ID,  -IA,      IC },    // 10
        { 0.0f,-1.0f,    0.0f }
    };

    // { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 4 }, { 0, 4, 5 }, { 0, 5, 1 }, // ファン, 上側
    // {11, 6, 7 }, {11, 7, 8 }, {11, 8, 9 }, {11, 9,10 }, {11,10, 6 }, // ファン, 下側
    // トライアングルファン 7頂点 * 2
    final int FAN_IDX[] = {
         0, 1, 2, 3, 4, 5, 1,
        11, 6,10, 9, 8, 7, 6
    };
    // ストリップは以下のようにつながる
    // 1 2 3 4 5 1
    //  6 7 8 9 0 6 (0=10)
    final int STRIP_IDX[] = {
         1, 6, 2, 7, 3, 8, 4, 9, 5,10, 1, 6
    };
    final float radius = shape.radius;
    Vector3f vtx[] = new Vector3f[12];
    for( int i = 0; i < 12; i++ ) {
        vtx[i] = new Vector3f( VTX[i][0], VTX[i][1], VTX[i][2] );
        vtx[i].multiply( radius );
        vtx[i].add( shape.center );
    }
    final int FAN_VERTEX_CNT = 7;
    gl.glBegin( GL.GL_TRIANGLE_FAN );
    for( int i = 0; i < FAN_VERTEX_CNT; i++ ) {
        gl.glVertex3f( vtx[FAN_IDX[i]].x, vtx[FAN_IDX[i]].y, vtx[FAN_IDX[i]].z );
    }
    gl.glEnd();
    gl.glBegin( GL.GL_TRIANGLE_FAN );
    for( int i = 0; i < FAN_VERTEX_CNT; i++ ) {
        gl.glVertex3f( vtx[FAN_IDX[7+i]].x, vtx[FAN_IDX[7+i]].y, vtx[FAN_IDX[7+i]].z );
    }
    gl.glEnd();

    // ストリップで真ん中の帯を描く
    final int STRIP_VERTEX_CNT = 12;
    gl.glBegin( GL.GL_TRIANGLE_STRIP );
    for( int i = 0; i < STRIP_VERTEX_CNT; i++ ) {
        gl.glVertex3f( vtx[STRIP_IDX[i]].x, vtx[STRIP_IDX[i]].y, vtx[STRIP_IDX[i]].z );
    }
    gl.glEnd();
}

同じようにアプレットをここに。
制止していたら話からづらいのでカメラをくるくる回すようにした。
見てわかるけど、これでは球とははほど遠い。
球に近づけるには、各三角形のそれぞれの辺の中点を求め、三角形を4分割し、中点の頂点を正規化する。
これを必要なだけ繰り返し球を作る。
特に必要なかったので、このソースは書いていないが、頂点のインデックスを持った辺 ( Edge ) とトライアングルのクラスを作ってやれば、それほど難しくないと思う。
ただ、実際にゲーム等で表示するのなら、モデリングソフトで簡単に球が作れるので、そこからデータ取ってきてそれを表示した方が楽だし早い。
だから、あんまり使うことはないと思う。



投稿者 Takenori : 2011年06月17日 21:08




comments powered by Disqus
Total : Today : Yesterday : なかのひと