C言語+GLUT(注視点を変える)

続きです。
前回のプログラムから、world_mapの配列を少し増やして、日本っぽくしてみました。このような画像になります。

プログラムを見ていきます。 ソースファイルは相変わらず1ファイルです。増えすぎると管理できなくなるのである程度大きくなってから分割する予定です。

takk@deb9:~$ cat -n cube.c
     1  #include <stdio.h>
     2  #include <GL/glut.h>
     3  #include <math.h>
     4
     5  GLdouble world_map[][3]={
     6          {0,0,16},
     7          {2,0,9},
     8          {2,0,10},

     ~省略~

    60          {14,0,4},
    61          {15,0,3},
    62  };
    63
    64  int world_size;

この配列をたくさんに増やしました。値が埋め込んでありますが、いずれ外部ファイルからロードするように変更するので、気にしません。Xが配列[0]、Yが配列[1]、Zが配列[2]となっていてとても分かりにくいのですが、こちらも必要に迫られてから構造体を使おうかと。

    65  GLdouble player_pos[3];
    66  GLdouble player_lookat[3];
    67  int deg;
    68  int wire_flag = 0;
    69
    70  GLdouble vertex[8][3]={
    71          {0,0,0},
    72          {1,0,0},
    73          {1,1,0},
    74          {0,1,0},
    75          {0,0,1},
    76          {1,0,1},
    77          {1,1,1},
    78          {0,1,1},
    79  };
    80
    81  int face[][4] = {
    82    { 0, 1, 2, 3 },
    83    { 1, 5, 6, 2 },
    84    { 5, 4, 7, 6 },
    85    { 4, 0, 3, 7 },
    86    { 4, 5, 1, 0 },
    87    { 3, 2, 6, 7 }
    88  };
    89
    90  GLdouble color[][3] = {
    91    { 1.0, 0.0, 0.0 },
    92    { 0.0, 1.0, 0.0 },
    93    { 0.0, 0.0, 1.0 },
    94    { 1.0, 1.0, 0.0 },
    95    { 1.0, 0.0, 1.0 },
    96    { 0.0, 1.0, 1.0 }
    97  };
    98
    99  GLdouble normal[][3] = {
   100    { 0.0, 0.0,-1.0 },
   101    { 1.0, 0.0, 0.0 },
   102    { 0.0, 0.0, 1.0 },
   103    {-1.0, 0.0, 0.0 },
   104    { 0.0,-1.0, 0.0 },
   105    { 0.0, 1.0, 0.0 }
   106  };
   107
   108  GLfloat light0pos[] = { 0.0, 3.0, 5.0, 1.0 };
   109  GLfloat light1pos[] = { 5.0, 3.0, 0.0, 1.0 };
   110

前回載せたGLUTのページ(書籍も買ってしまいましたが)を参考に作ってます。

   111  GLfloat yellow[] = { 0.6, 0.6, 0.1, 1.0 };
   112  GLfloat gold[] = { 0.89, 0.65, 0.1, 1.0 };
   113

色データは最初yellowを使ってましたが、日本を金色に光らせたかったのでgoldに入れ替えました。

   114  int edge[12][2]={
   115          {0,1},
   116          {1,2},
   117          {2,3},
   118          {3,0},
   119          {4,5},
   120          {5,6},
   121          {6,7},
   122          {7,4},
   123          {0,4},
   124          {1,5},
   125          {2,6},
   126          {3,7},
   127  };
   128
   129  void set_cube(GLdouble pos[])
   130  {
   131          int i,j;
   132          GLdouble v[3];
   133
   134          glBegin(GL_QUADS);
   135          for(j=0; j<6; j++){
   136                  glNormal3dv(normal[j]);
   137                  for(i=0; i<4; i++){
   138                          v[0]=vertex[face[j][i]][0]+pos[0];
   139                          v[1]=vertex[face[j][i]][1]+pos[1];
   140                          v[2]=vertex[face[j][i]][2]+pos[2];
   141                          glVertex3dv(v);
   142                  }
   143          }
   144          glEnd();
   145  }
   146
   147  void set_wire_cube(GLdouble pos[])
   148  {
   149          int i;
   150          GLdouble v[3];
   151
   152          glBegin(GL_LINES);
   153          for(i=0; i<12; i++){
   154                  v[0]=vertex[edge[i][0]][0]+pos[0];
   155                  v[1]=vertex[edge[i][0]][1]+pos[1];
   156                  v[2]=vertex[edge[i][0]][2]+pos[2];
   157                  glVertex3dv(v);
   158
   159                  v[0]=vertex[edge[i][1]][0]+pos[0];
   160                  v[1]=vertex[edge[i][1]][1]+pos[1];
   161                  v[2]=vertex[edge[i][1]][2]+pos[2];
   162                  glVertex3dv(v);
   163          }
   164          glEnd();
   165  }
   166

元のset_cubeをset_wire_cubeに改名して、新しく作ったset_cubeの方は面ありのブロックを設置する関数にしました。

   167  void look()
   168  {
   169          gluLookAt(
   170                  40 * cos((double)deg*M_PI/180.0),
   171                  player_pos[1],
   172                  40 * sin((double)deg*M_PI/180.0),
   173                  player_lookat[0],
   174                  player_lookat[1],
   175                  player_lookat[2],
   176                  0.0, 1.0, 0.0);
   177  }
   178

gluLookAtの第1~3引数は、視点、つまりカメラ(自分)の設置位置になります。
第4~6引数が、注視点で見ている対象になります。
この関数は、対象は動かさず、自分が対象の周りをぐるぐる回る処理です。

   179  void callback_display()
   180  {
   181          int i;
   182
   183          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   184
   185          glLoadIdentity();
   186
   187          look();
   188
   189          glLightfv(GL_LIGHT0, GL_POSITION, light0pos);
   190          glLightfv(GL_LIGHT1, GL_POSITION, light1pos);
   191
   192          glPushMatrix();
   193
   194          glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gold);
   195
   196          for(i=0;i<world_size;i++)
   197                  if(wire_flag)
   198                          set_cube(world_map[i]);
   199                  else
   200                          set_wire_cube(world_map[i]);
   201
   202          glPopMatrix();
   203          glutSwapBuffers();
   204          glFlush();
   205  }
   206
   207  void callback_reshape(int w, int h)
   208  {
   209          glViewport(0,0, w,h);
   210
   211          glMatrixMode(GL_PROJECTION);
   212          glLoadIdentity();
   213          gluPerspective(30,(double)w/(double)h, 1,100);
   214
   215          glMatrixMode(GL_MODELVIEW);
   216          glLoadIdentity();
   217          look();
   218  }
   219
   220  void callback_keyboard(unsigned char key, int x, int y)
   221  {
   222          switch (key) {
   223          case 'q': exit(0); break;
   224          case 'w': exit(0); break;
   225          case 's': exit(0); break;
   226          case 'a':
   227                  deg++;
   228                  if(deg >= 360)deg=0;
   229                  glutPostRedisplay();
   230                  break;
   231          case 'd':
   232                  deg--;
   233                  if(deg < 0)deg=359;
   234                  glutPostRedisplay();
   235                  break;
   236          case ' ':
   237                  wire_flag = 1 - wire_flag;
   238                  glutPostRedisplay();
   239                  break;
   240          default:
   241                  break;
   242          }
   243  }
   244

スペースキーを押すと、ワイヤーでの表示と、面ありの表示を切り替えられます。
Aキーは左回転、Dキーを右回転します。

   245  int main(int argc, char *argv[])
   246  {
   247          world_size = sizeof(world_map)/sizeof(GLdouble)/3;
   248
   249          player_pos[0]=0;
   250          player_pos[1]=30;
   251          player_pos[2]=0;
   252          player_lookat[0]=8;
   253          player_lookat[1]=0;
   254          player_lookat[2]=8;
   255          wire_flag = 0;
   256          deg = 0;
   257
   258          glutInit(&argc, argv);
   259          glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
   260          glutCreateWindow(argv[0]);
   261          glutDisplayFunc(callback_display);
   262          glutReshapeFunc(callback_reshape);
   263          glutKeyboardFunc(callback_keyboard);
   264
   265          glClearColor(1,1,1,1);
   266          glEnable(GL_DEPTH_TEST);
   267          glEnable(GL_CULL_FACE);
   268          glCullFace(GL_FRONT);
   269          glEnable(GL_LIGHTING);
   270          glEnable(GL_LIGHT0);
   271          glEnable(GL_LIGHT1);
   272          glLightfv(GL_LIGHT1, GL_DIFFUSE, gold);
   273          glLightfv(GL_LIGHT1, GL_SPECULAR, gold);
   274
   275          glutMainLoop();
   276          return 0;
   277  }
   278
takk@deb9:~$

GLUT理解をほとんどしてませんが、見よう見まねで作っていこうと思います。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA