ディスプレイリスト
ディスプレイリストとは
ディスプレイリストは、あとで実行できるコマンドをグループとして保存(コンパイル)するための仕組みです。
リストが生成されると、頂点とピクセルデータを評価してサーバマシン上のメモリにコピー(コンパイル)されます。メモリにコピーされるのは最初の一回だけなので、何度も複数コマンドをサーバーに送らなくて住むため、描画の高速化が期待できます。
リストが生成されると、頂点とピクセルデータを評価してサーバマシン上のメモリにコピー(コンパイル)されます。メモリにコピーされるのは最初の一回だけなので、何度も複数コマンドをサーバーに送らなくて住むため、描画の高速化が期待できます。
ただし、ディスプレイリストには欠点があります。それは、一度ディスプレイリストをコンパイルするとあとで変更することができません。頻繁に変更する場合は、代わりに頂点配列や頂点バッファオブジェクト(VBO)を使う必要があります。
また、ディスプレイリストは、すべてのコマンドを保存できるわけではないことに注意が必要です。
使い方
// ディスプレイリストを作成する
GLuint index = glGenLists(1);
// コマンドを保存する
glNewList(index, GL_COMPILE);
glBegin(GL_TRIANGLES);
glVertex3fv(v0);
glVertex3fv(v1);
glVertex3fv(v2);
glEnd();
glEndList();
...
// ディスプレイリストを使う
glCallList(index);
...
// 削除する
glDeleteLists(index, 1);
ディスプレイリストを使ったサンプル
例によって、3つの関数と、1つのディスプレイリスト用関数で説明します。
- createCube : ディスプレイリスト用関数
- initializeGL : 初期化処理
- resizeGL : リサイズ処理
- paintGL : 描画処理
GLuint cubeList; // ディスプレイリストのための変数
GLuint createCube()
{
GLuint index = glGenLists(1);
float lx = 0.5f;
float ly = 0.5f;
float lz = 0.5f;
glNewList(index, GL_COMPILE);
// sides
glBegin (GL_TRIANGLE_STRIP);
glNormal3f (-1,0,0);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,-ly,lz);
glVertex3f (-lx,ly,-lz);
glVertex3f (-lx,ly,lz);
glNormal3f (0,1,0);
glVertex3f (lx,ly,-lz);
glVertex3f (lx,ly,lz);
glNormal3f (1,0,0);
glVertex3f (lx,-ly,-lz);
glVertex3f (lx,-ly,lz);
glNormal3f (0,-1,0);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,-ly,lz);
glEnd();
// top face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,1);
glVertex3f (-lx,-ly,lz);
glVertex3f (lx,-ly,lz);
glVertex3f (lx,ly,lz);
glVertex3f (-lx,ly,lz);
glEnd();
// bottom face
glBegin (GL_TRIANGLE_FAN);
glNormal3f (0,0,-1);
glVertex3f (-lx,-ly,-lz);
glVertex3f (-lx,ly,-lz);
glVertex3f (lx,ly,-lz);
glVertex3f (lx,-ly,-lz);
glEnd();
glEndList();
return index;
}
createCubeでは、立方体の頂点データglBegin()からglEnd()までをディスプレイリストtとして保存し、その番号を返します。
この処理で、頂点データが評価されサーバー上のメモリへとコピーされます。
この関数が呼び鋳出されるのは、initializeGL中の1回だけです。
この処理で、頂点データが評価されサーバー上のメモリへとコピーされます。
この関数が呼び鋳出されるのは、initializeGL中の1回だけです。
void initializeGL()
{
glClearColor(0.5, 0.5, 0.5, 1.0);
glEnable(GL_DEPTH_TEST);
//カリング:表面のみ表示
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
//光源有効
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//光源の設定
GLfloat light_position[] = { -50.0, 50.0, 50.0, 1.0 };
GLfloat light_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
glLightfv( GL_LIGHT0, GL_POSITION, light_position );
glLightfv( GL_LIGHT0, GL_AMBIENT, light_ambient );
glLightfv( GL_LIGHT0, GL_DIFFUSE, light_diffuse );
glLightfv( GL_LIGHT0, GL_SPECULAR, light_specular );
cubeList = createCube(); // ディスプリリスト生成
}
initializeGLにて、createCubeを1度だけ呼び出します。
ディスプレイリストの番号をcubeListとします。
ディスプレイリストの番号をcubeListとします。
void resizeGL( int w, int h )
{
glViewport(0, 0, w, h);
//プロジェクション・マトリックス設定
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0);
}
void paintGL()
{
static GLfloat angle = 0.0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//モデル・ビュー・マトリックス設定
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
//カメラ設定
gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glPushMatrix();
{ // 直方体の表示
//材質設定
GLfloat red[] = { 0.8, 0.2, 0.2, 1.0 };
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
glRotatef(angle, 0.0, 1.0, 0.0);
glCallList(cubeList); // ディスプレイリスト呼びだし
}
glPopMatrix();
angle = (angle>360.0) ? angle-360.0 : angle+1;
}
paintGLにて、ディスプレイリストをよびだします。
呼び出す方法は、glCallList(cubeList)です。
これにより、glBegin~glEndといったアプリケーションとサーバー間での30以上のコマンドやり取りが、glCallListの1回だけとなりました。
呼び出す方法は、glCallList(cubeList)です。
これにより、glBegin~glEndといったアプリケーションとサーバー間での30以上のコマンドやり取りが、glCallListの1回だけとなりました。
単純な立方体の描画にくらべ、
ディスプレイリストを使用すると、paintGLの1回の処理で呼び出されるAPI(コマンド)の数が少なくなっているのがわかります。
物体が1つだけだとおそらく速度的にはそれほど大差ないかもしれませんが、複数の物体を表示させるような場合には速度の違いが出てくるはずです。
ディスプレイリストを使用すると、paintGLの1回の処理で呼び出されるAPI(コマンド)の数が少なくなっているのがわかります。
物体が1つだけだとおそらく速度的にはそれほど大差ないかもしれませんが、複数の物体を表示させるような場合には速度の違いが出てくるはずです。
参考
まとめ
頂点配列やVBOが当たり前の時代に、OpenGL1.0時代のディスプレイリストをいまさら!!と思いますが、パワーのないNotePCなんかはOpenGL2.xすら対応してなかったりするので、ディスプレイリストはまだまだ使いどころがあります。
といっても、やはり古い機能であるため今後使われていくことは少なくなるでしょうね。
といっても、やはり古い機能であるため今後使われていくことは少なくなるでしょうね。