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


コメント