上一次寫了OpenGL的幾何變換3之內觀察全景圖
上次采用的是圖片分割化方式,這次采用數據分割化方式。
先說下思路,數據分割化方式呢,是只讀取一張圖片imgData,然后通過glTexCoord2f()配置紋理坐標和glVertex3f()配置圖形坐標,然后該分隔的分隔,該組合的組合。
這次的代碼使用的圖片處理結果有些瑕疵,因為一張完整的全景圖片是有角度拉伸的,且有些模糊化,將就着看吧
附上代碼:
1 #include <stdio.h> 2 #include <math.h> 3 #include <windows.h> 4 #include <gl/glut.h> //引用相關包 5 #include <gl/glaux.h> 6 7 #define pi 3.141592654 8 9 GLfloat xangle = 0.0; //X 旋轉量 10 GLfloat yangle = 0.0; //Y 旋轉量 11 GLfloat zangle = 0.0; //Z 旋轉量 12 GLuint textureArr[1]; //存儲6個紋理 13 14 //交叉點的坐標 15 int cx = 0; 16 int cy = 0; 17 18 float vertex[61][31][3]; 19 float texpoint[61][31][2]; 20 21 //載入位圖圖象 22 AUX_RGBImageRec *loadBMP(CHAR *Filename) 23 { 24 FILE *File = NULL; //文件句柄 25 if (!Filename) //確保文件名已提供 26 { 27 return NULL; //如果沒提供,返回 NULL 28 } 29 30 File = fopen(Filename,"r"); //嘗試打開文件 31 if (File) //文件存在么? 32 { 33 fclose(File); //關閉句柄 34 return auxDIBImageLoadA(Filename); //載入位圖並返回指針 35 } 36 return NULL; //如果載入失敗,返回 NULL 37 } 38 39 //載入位圖(調用上面的代碼)並轉換成紋理 40 int loadGLTexture2() 41 { 42 int Status = FALSE; //狀態指示器 43 AUX_RGBImageRec *textureImage[1]; //創建紋理的存儲空間 44 45 memset(textureArr, 0x0, sizeof(textureArr)); 46 memset(textureImage,0,sizeof(textureImage)); //將指針設為NULL 47 48 //載入位圖,檢查有無錯誤,如果位圖沒找到則退出 49 if (textureImage[0] = loadBMP("pano/pano_sphere.bmp")) 50 { 51 Status = TRUE; //將 Status 設為 TRUE 52 glGenTextures(1, &textureArr[0]); //創建紋理 53 54 //使用來自位圖數據生成 的典型紋理 55 glBindTexture(GL_TEXTURE_2D, textureArr[0]); 56 //生成紋理 57 glTexImage2D(GL_TEXTURE_2D, 0, 3, textureImage[0]->sizeX, textureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImage[0]->data); 58 59 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //線形濾波 60 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //線形濾波 61 } 62 63 if (textureImage[0]) //紋理是否存在 64 { 65 if (textureImage[0]->data) //紋理圖像是否存在 66 { 67 free(textureImage[0]->data); //釋放紋理圖像占用的內存 68 } 69 free(textureImage[0]); //釋放圖像結構 70 } 71 72 return Status; //返回 Status 73 } 74 75 //從這里開始進行所有的繪制 76 void drawCube(void) 77 { 78 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度緩存 79 glMatrixMode(GL_MODELVIEW); 80 glLoadIdentity(); //重置當前的模型觀察矩陣 81 82 glPushMatrix(); 83 { 84 gluLookAt(0, 0, -5, 0, 0, 0, 0, 1, 0); 85 glTranslatef(0.0f, 0.0f, -5.0f); //移入屏幕 5 個單位 86 glRotatef(xangle, 1.0f, 0.0f, 0.0f); //繞X軸旋轉 87 glRotatef(yangle, 0.0f, 1.0f, 0.0f); //繞Y軸旋轉 88 glRotatef(zangle, 0.0f, 0.0f, 1.0f); //繞Z軸旋轉 89 90 #if (0) 91 glBindTexture(GL_TEXTURE_2D, textureArr[0]); //選擇紋理 92 glBegin(GL_QUADS); { 93 //前面:紋理順時針,立方體逆時針 94 float fx = 1024.0/8.0; 95 float fy = 512.0/4.0; 96 97 float tx0 = fx*3.0/1024.0; 98 float ty0 = fy*1.0/512.0; 99 float tx1 = fx*5.0/1024.0; 100 float ty1 = fy*3.0/512.0; 101 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*1.0, ty0, fx*5.0, tx1, fy*3.0, ty1); 102 glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, 1.0f); //紋理和四邊形的左下 103 glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, 1.0f); //紋理和四邊形的左上 104 glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, 1.0f); //紋理和四邊形的右上 105 glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, 1.0f); //紋理和四邊形的右下 106 107 //后面:紋理順時針,立方體逆時針 108 tx0 = fx*0.0/1024.0; 109 ty0 = fy*1.0/512.0; 110 tx1 = fx*1.0/1024.0; 111 ty1 = fy*3.0/512.0; 112 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*0.0, tx0, fy*1.0, ty0, fx*1.0, tx1, fy*3.0, ty1); 113 glTexCoord2f(tx0, ty0); glVertex3f( 0.0f, -1.0f, -1.0f); //紋理和四邊形的左下 114 glTexCoord2f(tx0, ty1); glVertex3f( 0.0f, 1.0f, -1.0f); //紋理和四邊形的左上 115 glTexCoord2f(tx1, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //紋理和四邊形的右上 116 glTexCoord2f(tx1, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //紋理和四邊形的右下 117 118 tx0 = fx*7.0/1024.0; 119 ty0 = fy*1.0/512.0; 120 tx1 = fx*8.0/1024.0; 121 ty1 = fy*3.0/512.0; 122 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*7.0, tx0, fy*1.0, ty0, fx*8.0, tx1, fy*3.0, ty1); 123 glTexCoord2f(tx0, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //紋理和四邊形的左下 124 glTexCoord2f(tx0, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //紋理和四邊形的左上 125 glTexCoord2f(tx1, ty1); glVertex3f( 0.0f, 1.0f, -1.0f); //紋理和四邊形的右上 126 glTexCoord2f(tx1, ty0); glVertex3f( 0.0f, -1.0f, -1.0f); //紋理和四邊形的右下 127 128 //頂面:紋理順時針,立方體逆時針 129 tx0 = fx*3.0/1024.0; 130 ty0 = fy*3.0/512.0; 131 tx1 = fx*5.0/1024.0; 132 ty1 = fy*4.0/512.0; 133 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*3.0, ty0, fx*5.0, tx1, fy*4.0, ty1); 134 glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, 1.0f, 1.0f); //紋理和四邊形的左下 135 glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //紋理和四邊形的左上 136 glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //紋理和四邊形的右上 137 glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, 1.0f, 1.0f); //紋理和四邊形的右下 138 139 //底面:紋理順時針,立方體逆時針 140 tx0 = fx*3.0/1024.0; 141 ty0 = fy*0.0/512.0; 142 tx1 = fx*5.0/1024.0; 143 ty1 = fy*1.0/512.0; 144 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*3.0, tx0, fy*0.0, ty0, fx*5.0, tx1, fy*1.0, ty1); 145 glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //紋理和四邊形的左下 146 glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, -1.0f, 1.0f); //紋理和四邊形的左上 147 glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, -1.0f, 1.0f); //紋理和四邊形的右上 148 glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //紋理和四邊形的右下 149 150 //左面:紋理順時針,立方體逆時針 151 tx0 = fx*1.0/1024.0; 152 ty0 = fy*1.0/512.0; 153 tx1 = fx*3.0/1024.0; 154 ty1 = fy*3.0/512.0; 155 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*1.0, tx0, fy*1.0, ty0, fx*3.0, tx1, fy*3.0, ty1); 156 glTexCoord2f(tx0, ty0); glVertex3f( 1.0f, -1.0f, -1.0f); //紋理和四邊形的左下 157 glTexCoord2f(tx0, ty1); glVertex3f( 1.0f, 1.0f, -1.0f); //紋理和四邊形的左上 158 glTexCoord2f(tx1, ty1); glVertex3f( 1.0f, 1.0f, 1.0f); //紋理和四邊形的右上 159 glTexCoord2f(tx1, ty0); glVertex3f( 1.0f, -1.0f, 1.0f); //紋理和四邊形的右下 160 161 //右面:紋理順時針,立方體逆時針 162 tx0 = fx*5.0/1024.0; 163 ty0 = fy*1.0/512.0; 164 tx1 = fx*7.0/1024.0; 165 ty1 = fy*3.0/512.0; 166 //printf("x0=%.f(%.3f), y0=%.f(%.3f), x1=%.f(%.3f), y1=%.f(%.3f)\n", fx*5.0, tx0, fy*1.0, ty0, fx*7.0, tx1, fy*3.0, ty1); 167 glTexCoord2f(tx0, ty0); glVertex3f(-1.0f, -1.0f, 1.0f); //紋理和四邊形的左下 168 glTexCoord2f(tx0, ty1); glVertex3f(-1.0f, 1.0f, 1.0f); //紋理和四邊形的左上 169 glTexCoord2f(tx1, ty1); glVertex3f(-1.0f, 1.0f, -1.0f); //紋理和四邊形的右上 170 glTexCoord2f(tx1, ty0); glVertex3f(-1.0f, -1.0f, -1.0f); //紋理和四邊形的右下 171 }glEnd(); 172 #else 173 glBindTexture(GL_TEXTURE_2D, textureArr[0]); // 選擇紋理,有多個紋理時這句話是必要de 174 glBegin(GL_QUADS); { //四邊形繪制開始 175 for(int i=0; i<60; i++) { 176 for(int j=0; j<30; j++) { 177 //第一個紋理坐標(左下角) 178 glTexCoord2f(texpoint[i][j][0], texpoint[i][j][1]); 179 glVertex3f(vertex[i][j][0], vertex[i][j][1], vertex[i][j][2]); 180 181 //第二個紋理坐標(左上角) 182 glTexCoord2f(texpoint[i][j][0], texpoint[i][j+1][1]); 183 glVertex3f(vertex[i][j+1][0], vertex[i][j+1][1], vertex[i][j+1][2]); 184 185 //第三個紋理坐標(右上角) 186 glTexCoord2f(texpoint[i+1][j+1][0], texpoint[i+1][j+1][1]); 187 glVertex3f(vertex[i+1][j+1][0], vertex[i+1][j+1][1], vertex[i+1][j+1][2]); 188 189 //第四個紋理坐標(右下角) 190 glTexCoord2f(texpoint[i+1][j][0], texpoint[i][j][1]); 191 glVertex3f(vertex[i+1][j][0], vertex[i+1][j][1], vertex[i+1][j][2]); 192 } 193 } 194 }glEnd(); 195 #endif 196 }glPopMatrix(); 197 glFlush(); 198 } 199 200 //初始化 201 void init(void) 202 { 203 glClearColor (0.0, 0.0, 0.0, 0.0); //清理顏色,為黑色,(也可認為是背景顏色) 204 205 glCullFace(GL_FRONT); //背面裁剪(背面不可見) 206 glEnable(GL_CULL_FACE); //啟用裁剪 207 glEnable(GL_TEXTURE_2D); 208 loadGLTexture2(); //載入紋理貼圖 209 210 //初始化數據 211 for(int i=0; i<=360; i+=6) 212 { 213 for( int j=180; j>=0; j-=6) 214 { 215 vertex[i/6][(180-j)/6][0] = cos((float)i/180.0*pi)*sin((float)j/180.0*pi)*2; 216 vertex[i/6][(180-j)/6][1] = cos((float)j/180.0*pi)*2; 217 vertex[i/6][(180-j)/6][2] = sin((float)i/180.0*pi)*sin((float)j/180.0*pi)*2; 218 } 219 } 220 for(int i=0; i<61; i++) 221 { 222 for(int k=0; k<31; k++) 223 { 224 texpoint[i][k][0]= (float)i/60.0; //生成X浮點值 225 texpoint[i][k][1]= (float)k/30.0; //生成Y浮點值 226 } 227 } 228 printf("...\n"); 229 } 230 231 void display(void) 232 { 233 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清楚顏色數據和深度數據(清屏) 234 glLoadIdentity(); //Reset The View 235 236 drawCube(); 237 238 glutSwapBuffers(); //交換緩沖區。顯示圖形 239 240 //xangle += 0.3f; 241 //yangle += 0.3f; 242 //zangle += 0.3f; 243 Sleep(10); 244 } 245 246 //當窗口大小改變時,會調用這個函數 247 void reshape(GLsizei w,GLsizei h) 248 { 249 glViewport(0,0,w,h); //設置視口 250 glMatrixMode(GL_PROJECTION); //設置矩陣模式為投影變換矩陣, 251 glLoadIdentity(); //變為單位矩陣 252 gluPerspective(110, (GLfloat)w / h, 0.1f, 100.0f); //設置投影矩陣 253 glMatrixMode(GL_MODELVIEW); //設置矩陣模式為視圖矩陣(模型) 254 glLoadIdentity(); //變為單位矩陣 255 } 256 257 //處理鼠標點擊 258 void Mouse(int button, int state, int x, int y) 259 { 260 if(state == GLUT_DOWN) //第一次鼠標按下時,記錄鼠標在窗口中的初始坐標 261 { 262 //記住鼠標點擊后光標坐標 263 cx = x; 264 cy = y; 265 //printf("Mouse: x=%d, y=%d, oldx_Translatef=%f, oldy_Translatef=%f\n", x, y, oldx_Translatef, oldy_Translatef); 266 } 267 } 268 269 //處理鼠標拖動 270 void onMouseMove(int x, int y) 271 { 272 float offset = 0.18; 273 //計算拖動后的偏移量,然后進行xy疊加減 274 yangle -= ((x - cx) * offset); 275 276 if (xangle < 90 && y > cy) {//往下拉 277 xangle += ((y - cy) * offset); 278 } else if (xangle > -90 && y < cy) {//往上拉 279 xangle += ((y - cy) * offset); 280 } 281 //printf("Move: x=%d(%d)[%d], y=%d(%d)[%d], xangle_Textures=%f, yangle_Textures=%f\n", 282 // x, cx_Textures, x-cx_Textures, 283 // y, cy_Textures, y-cy_Textures, 284 // xangle_Textures, yangle_Textures); 285 glutPostRedisplay(); 286 287 //保存好當前拖放后光標坐標點 288 cx = x; 289 cy = y; 290 } 291 292 //鍵盤輸入事件函數 293 void keyboard(unsigned char key,int x,int y) 294 { 295 switch(key) 296 { 297 case 'x': //當按下鍵盤上d時,以沿X軸旋轉為主 298 if (xangle < 85.0f) 299 { 300 xangle += 1.0f; //設置旋轉增量 301 } 302 break; 303 case 'X': 304 if (xangle > -85.0f) 305 { 306 xangle -= 1.0f; //設置旋轉增量 307 } 308 break; 309 case 'y': 310 yangle += 1.0f; 311 break; 312 case 'Y': 313 yangle -= 1.0f; 314 break; 315 //case 'z': 316 // zangle += 1.0f; 317 // break; 318 //case 'Z': 319 // zangle -= 1.0f; 320 // break; 321 default: 322 return; 323 } 324 glutPostRedisplay(); //重繪函數 325 } 326 327 //特殊按鍵 328 void specialKey(int key, int x, int y) 329 { 330 float offset = 1.5; 331 switch (key) 332 { 333 case GLUT_KEY_UP: //腦袋向上往前看 334 if (xangle < 90.0f) 335 { 336 xangle += offset; //設置旋轉增量 337 } 338 break; 339 case GLUT_KEY_DOWN: //腦袋向下往前看 340 if (xangle > -90.0f) 341 { 342 xangle -= offset; //設置旋轉增量 343 } 344 break; 345 case GLUT_KEY_LEFT: //腦袋想左往前看 346 yangle -= offset; 347 break; 348 case GLUT_KEY_RIGHT: //腦袋向右往前看 349 yangle += offset; 350 break; 351 default: 352 break; 353 } 354 glutPostRedisplay(); 355 } 356 357 int main(int argc, char *argv[]) 358 { 359 printf("可通過↑↓←→按鍵控制全景圖繞旋轉\n"); 360 361 glutInit(&argc, argv); //固定格式 362 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); 363 glutInitWindowSize(512, 512); //顯示框的大小 364 glutInitWindowPosition(100,100); //確定顯示框左上角的位置 365 glutCreateWindow("OpenGL紋理貼圖"); 366 367 init(); //初始化資源,這里一定要在創建窗口以后,不然會無效。 368 glutDisplayFunc(display); 369 //glutIdleFunc(display); 370 glutReshapeFunc(reshape); //繪制圖形時的回調 371 glutMouseFunc(Mouse); 372 glutMotionFunc(onMouseMove); 373 glutKeyboardFunc(keyboard); 374 glutSpecialFunc(specialKey); // 特殊按鍵 375 glutMainLoop(); 376 return 0; 377 }
執行結果:
附上執行程序鏈接: https://pan.baidu.com/s/1dSVNP0 密碼: 8anf