OpenGl 實現滑鼠分別移動多個物體 ———-移動一個物體另外一個物體不動–讀取多個3d模型操作的前期踏腳石

  • 2019 年 10 月 3 日
  • 筆記

原文作者:aircraft

原文鏈接:https://www.cnblogs.com/DOMLX/p/11620088.html

 

 

 

前言:

  因為接下來的項目需求是要讀取多個3D模型,並且移動拼接,那麼我就先實現滑鼠控制兩個物體移動互不干擾來當踏腳石。

 

 

 

一.滑鼠控制函數準備

  我們需要對滑鼠資訊的獲取,那麼必然需要一個滑鼠事件的響應函數來控制,很好opengl已經有內部的滑鼠控制函數了,我們直接拿來使用就行了。

 

glutMouseFunc( (void*)Func(int button, int state, int x, int y) );
glutMouseFunc這個是調用滑鼠函數的入口,func是我們給滑鼠處理函數的命名, 三個參數分別是滑鼠響應的事件類型,比如左鍵點擊,右鍵點擊之類,x,y則是當前滑鼠在窗口的位置坐標。

下面這個是處理滑鼠移動時候的調用函數
glutMotionFunc(&func(int x,inty)); // 滑鼠移動的時候的函數 x,y當前滑鼠坐標

反正調用起來非常的簡單只要自己寫好一個滑鼠點擊類事件處理函數和一個滑鼠移動事件處理函數,然後傳入進去就行了,調用函數放在main函數里。反正後面程式碼有。

比如:
// 滑鼠運動時  void onMouseMove(int x, int y) {      //當滑鼠狀態為按下時進入後續判斷      if (mousetate) {          //x對應y是因為對應的是法向量          if (choose == 1) {              movX1 = (x - x1) / width1;              glutPostRedisplay();              movY1 = -((y - Y1) / height1);              glutPostRedisplay();              std::cout << " 移動 x1 = " << x << " y1 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }          if (choose == 2) {              movX2 = (x - x2) / width2;              glutPostRedisplay();              movY2 = -((y - y2) / height2);              glutPostRedisplay();              std::cout << " 移動 x2 = " << x << " y2 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }      }  }          glutMotionFunc(&onMouseMove); // 滑鼠移動的時候的函數調用

 

二.一些滑鼠的響應事件

if(state == GLUT_DOWN) //相當於“如果某個滑鼠鍵被按下”
if(state == GLUT_UP) //相當於“如果某個滑鼠鍵被放開”
if(button == GLUT_LEFT_BUTTON) //相當於“如果滑鼠左鍵被按下或者被放開”
if(button == GLUT_RIGHT_BUTTON) //相當於“如果滑鼠右鍵被按下或被放開”
if(button == GLUT_MIDDLE_BUTTON) //相當於“如果滑鼠中鍵被按下或者被放開”

還有滑鼠的滾輪事件

GLUT_WHEEL_UP  

GLUT_WHEEL_DOWN

這兩個可能有時候會遇到自己gult庫沒有定義,那麼就是版本比較老的緣故,不想麻煩下新版本或者下了新版本還是沒有解決的話就直接像這樣定義在文件頭部:

#define  GLUT_WHEEL_UP 3           //定義滾輪操作
#define  GLUT_WHEEL_DOWN 4

 

三.實現過程介紹

  首先我們要畫出多個物體,那麼這個是入門就不講了。

  其次我們滑鼠要點擊選取一個物體,當我們滑鼠按住移動時,物體跟隨我們的滑鼠移動。按住滑鼠點擊選取的範圍可以是這個物體中心為定點坐標,以邊長為d的一個矩形區域,當滑鼠點擊在這個區域時,我們則判定選取了這個物體。

  當兩個物體重疊時,我們優先選取畫出的第一個物體進行移動。

 

  那麼問題就來了,選取了物體後,如何實現物體跟隨我們滑鼠移動呢?

  非常簡單,水平方向上,只要在滑鼠移動時將移動後的坐標減去移動前的坐標然後除以物體的寬度或者長度 ,就得到了移動的法向量。movX1 = (x – x1) / width1;

  垂直方向上,同理可得movY1 = -((y – Y1) / height1);  為什麼這裡多個負號,是因為向下移動是負數,向上是正數。

  

  然後將移動後改變的移動法向量,讓程式調用窗口重新繪製一次即可。如果出現閃爍問題,可以使用雙緩衝。

 

滑鼠點擊事件處理程式碼:

 整個程式碼唯一的坑就在兩行上,理解這兩行,那麼就毫無難度了 x1 = 400; Y1 = 400;

// 滑鼠交互  void myMouse(int button, int state, int x, int y)  {    //滑鼠左鍵按下或者鬆開      if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {          mousetate = 1;          if (!choose) {              if (x<(x1 + chooseWidth) && x>(x1 - chooseWidth)) {                  if (y<(Y1 + chooseHeight) && y>(Y1 - chooseHeight)) {                      x1 = 400;                      Y1 = 400;                      movX1 = (x - x1) / width1;                      movY1 = -((y - Y1) / height1);                      choose = 1;                  }              }              else if (x<(x2 + chooseWidth) && x>(x2 - chooseWidth)) {                  if (y<(y2 + chooseHeight) && y>(y2 - chooseHeight)) {                      x2 = 400;                      y2 = 400;                      movX2 = (x - x2) / width2;                      movY2 = -((y - y2) / height2);                      choose = 2;                  }              }            }          std::cout << "x = " << x << " y = " << y << std::endl;      }      if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {          if (choose == 1) {              x1 += (movX1*width1);              Y1 += -(movY1*height1);          }          if (choose == 2) {              x2 += (movX2*width2);              y2 += -(movY2*height2);          }          mousetate = 0;          choose = 0;          std::cout << "x = " << x1 << " y = " << Y1 << std::endl;      }        //滾輪事件      //scale 增加就是放大 減小就是縮小      //currentfile 對不同的模型用不用的scale      if (state == GLUT_UP && button == GLUT_WHEEL_UP) {        }      else scale = 0.2;      if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) {        }      else scale = 0.2;      //glutPostRedisplay();//促使主程式儘快的重繪窗口  }

 

 

 

滑鼠移動處理程式程式碼:
// 滑鼠運動時  void onMouseMove(int x, int y) {      //當滑鼠狀態為按下時進入後續判斷      if (mousetate) {          //x對應y是因為對應的是法向量          if (choose == 1) {              movX1 = (x - x1) / width1;              glutPostRedisplay();              movY1 = -((y - Y1) / height1);              glutPostRedisplay();              std::cout << " 移動 x1 = " << x << " y1 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }          if (choose == 2) {              movX2 = (x - x2) / width2;              glutPostRedisplay();              movY2 = -((y - y2) / height2);              glutPostRedisplay();              std::cout << " 移動 x2 = " << x << " y2 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }      }  }

 

我們預覽程式運行,分別控制兩個正方體的移動。

移動前:

 

 

移動後:

 

 

這個就是我們本文實現的內容,後面就可以用於讀取多個3d模型分別進行移動。

 

項目完整程式碼,配置好Opengl環境可以直接運行,更多項目分享以及學習教程,請關注在下!!!!:

#include <GL/glut.h>  #include <iostream>    // 繪製立方體      // 將立方體的八個頂點保存到一個數組裡面     static GLfloat vertex_list[][3] = {      -0.5f, -0.5f, -0.5f,       0.5f, -0.5f, -0.5f,      -0.5f,  0.5f, -0.5f,       0.5f,  0.5f, -0.5f,      -0.5f, -0.5f,  0.5f,       0.5f, -0.5f,  0.5f,      -0.5f,  0.5f,  0.5f,       0.5f,  0.5f,  0.5f,  };    // 將要使用的頂點的序號保存到一個數組裡面     static GLint index_list[][4] = {      0, 2, 3, 1,      0, 4, 6, 2,      0, 1, 5, 4,      4, 5, 7, 6,      1, 3, 7, 5,      2, 6, 7, 3,  };    #define  GLUT_WHEEL_UP 3           //定義滾輪操作  #define  GLUT_WHEEL_DOWN 4    const int windowsWidth = 800;  const int windowsHeight = 800;  GLfloat scale = 0.2;    GLfloat movX1 = -1.0f, movX2 = 1.0f, movY1 = 0.0f, movY2 = 0.0f;  GLfloat width1 = (windowsWidth / 2.0)*scale,height1 = (windowsHeight / 2)*scale;  GLfloat width2 = (windowsWidth / 2)*scale, height2 = (windowsHeight / 2)*scale;  GLfloat x1 = (windowsWidth / 2)+(width1*movX1), x2 = (windowsWidth / 2) + (width1*movX2), Y1 = (windowsHeight / 2)+(height1*movY1), y2 = (windowsHeight / 2) + (height1*movY2), z1 = 0.0f, z2 = 0.0f;  GLfloat chooseWidth = 20,chooseHeight = 20;  GLfloat dx = 0, dy = 0;  bool mousetate = 0;  int choose = 0;  // 滑鼠交互  void myMouse(int button, int state, int x, int y)  {    //滑鼠左鍵按下或者鬆開      if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {          mousetate = 1;          if (!choose) {              if (x<(x1 + chooseWidth) && x>(x1 - chooseWidth)) {                  if (y<(Y1 + chooseHeight) && y>(Y1 - chooseHeight)) {                      x1 = 400;                      Y1 = 400;                      movX1 = (x - x1) / width1;                      movY1 = -((y - Y1) / height1);                      choose = 1;                  }              }              else if (x<(x2 + chooseWidth) && x>(x2 - chooseWidth)) {                  if (y<(y2 + chooseHeight) && y>(y2 - chooseHeight)) {                      x2 = 400;                      y2 = 400;                      movX2 = (x - x2) / width2;                      movY2 = -((y - y2) / height2);                      choose = 2;                  }              }            }          std::cout << "x = " << x << " y = " << y << std::endl;      }      if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {          if (choose == 1) {              x1 += (movX1*width1);              Y1 += -(movY1*height1);          }          if (choose == 2) {              x2 += (movX2*width2);              y2 += -(movY2*height2);          }          mousetate = 0;          choose = 0;          std::cout << "x = " << x1 << " y = " << Y1 << std::endl;      }        //滾輪事件      //scale 增加就是放大 減小就是縮小      //currentfile 對不同的模型用不用的scale      if (state == GLUT_UP && button == GLUT_WHEEL_UP) {        }      else scale = 0.2;      if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) {        }      else scale = 0.2;      //glutPostRedisplay();//促使主程式儘快的重繪窗口  }    // 滑鼠運動時  void onMouseMove(int x, int y) {      //當滑鼠狀態為按下時進入後續判斷      if (mousetate) {          //x對應y是因為對應的是法向量          if (choose == 1) {              movX1 = (x - x1) / width1;              glutPostRedisplay();              movY1 = -((y - Y1) / height1);              glutPostRedisplay();              std::cout << " 移動 x1 = " << x << " y1 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }          if (choose == 2) {              movX2 = (x - x2) / width2;              glutPostRedisplay();              movY2 = -((y - y2) / height2);              glutPostRedisplay();              std::cout << " 移動 x2 = " << x << " y2 = " << y << std::endl;          }          else {              std::cout << "not choose" << std::endl;          }      }  }    // 繪製立方體    void DrawCube(void)  {      glPushMatrix();      glFrontFace(GL_CCW);//逆時針      glCullFace(GL_BACK);      glEnable(GL_CULL_FACE);      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);      int i, j;            glBegin(GL_QUADS);        //glBegin(GL_LINES);      for (i = 0; i < 6; ++i) // 12 條線段        {          for (j = 0; j < 4; ++j) // 每條線段 2個頂點            {              glVertex3fv(vertex_list[index_list[i][j]]);          }      }      glEnd();      }    static float rotate = 0;  static int times = 0;    void renderScene2(void)  {      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        glMatrixMode(GL_MODELVIEW);      glLoadIdentity();      glColor3f(0, 0, 1);      glScalef(0.3, 0.3, 0.3);    // 縮放      glPushMatrix();        //glTranslatef(-0.2, 0, 0); // 平移        //glScalef(2, 1, 1);    // 縮放          times++;      if (times > 100)      {          times = 0;      }        if (times % 100 == 0)      {          rotate += 0.3;      }        glPushMatrix();        glTranslatef(-2, 0, 0); // 平移      glRotatef(rotate, 0, 1, 0);      glRotatef(rotate, 1, 0, 0);      DrawCube();      glPopMatrix();        glTranslatef(2, 0, 0); // 平移      glRotatef(rotate, 0, 1, 0);      glRotatef(rotate, 1, 0, 0);      //glScalef(0.5, 0.5, 0.5);    // 縮放      DrawCube();        glPopMatrix();      glutSwapBuffers();  }  void renderScene(void)  {      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);      glMatrixMode(GL_MODELVIEW);      glLoadIdentity();          glScalef(scale, scale, scale);    // 縮放      glPushMatrix();      glColor3f(0, 0, 1);      glTranslatef(movX1, movY1, 0);      DrawCube();      glPopMatrix();        glPushMatrix();      glColor3f(0, 1, 0);      glTranslatef(movX2, movY2, 0);      DrawCube();      glPopMatrix();      glutSwapBuffers();  }    void main(int argc, char **argv)  {      glutInit(&argc, argv);      glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);      glutInitWindowPosition(100, 100);      glutInitWindowSize(windowsWidth, windowsHeight);      glutCreateWindow("GLDemo");      glutMouseFunc(&myMouse);        //滑鼠點擊處理函數      glutMotionFunc(&onMouseMove); // 滑鼠移動的時候的函數      glutDisplayFunc(&renderScene);      glutIdleFunc(&renderScene);        glutMainLoop();  }