続きです。
前回のプログラムから、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理解をほとんどしてませんが、見よう見まねで作っていこうと思います。
コメント