1. 程式人生 > >OpenGl 實現滑鼠分別移動多個物體 ----------移動一個物體另外一個物體不動--讀取多個3d模型操作的前期踏腳石

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

原文作者: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();
}

 

 

 

&n