鼠标拖动OpenGL / GLUT中的对象

时间:2013-11-29 15:19:24

标签: c++ opengl mouseevent

我一直在寻找一个简单程序的教程或示例代码 - 点击对象(例如2d矩形)然后当你按住并移动鼠标时,对象跟随鼠标,然后在鼠标释放时对象仍然在新位置。换句话说,我想了解如何使用鼠标事件拖放对象。

任何人都可以帮助我指出与此问题有关的任何有用信息来源的正确方向吗?

4 个答案:

答案 0 :(得分:6)

感谢目前为止的所有回复。

我已经知道如何做到这一点,所以我将继续回答我自己的问题。

我使用GLUT作为鼠标处理程序:

  1. 单击鼠标并移动(glutMotionFunc)时,将调用拖动功能。

  2. 在拖动功能中,鼠标坐标(x,y)在转换为窗口坐标时转换为Points结构。

  3. 如果鼠标位于正方形内,则通过更改其坐标并重新显示来拖动方块。

  4. 我仍然是OpenGL和C ++的新手,所以我为凌乱的编码道歉。我这样做有点沮丧,因为重绘的方块使得它看起来像是光标卡在中心。为了学习目的,我欢迎这个问题的替代解决方案和对我的代码的批评。

    CODE(包含过剩和使用命名空间std):

    // points structure made of two coordinates; x and y
    struct Points
    {
        float x,y;  // initializor
        Points() { x = 0.0; y = 0.0; } // constructor
    
        Points(float _x, float _y) : x(_x), y(_y) {}
    };
    
    // square made of 4 points
    class Square
    {
    public:
        Points pts[4]; // square structure
        Square(); // initialize constructor
    
        void draw(Square *sqr); // draw square
        Points mouse(int x, int y); // get mouse coordintaes
        Square* drag(Square *sqr, Points *mouse); // change points of sqr
    };
    
    // square constructor
    Square::Square()
    {
        pts[0] = Points(0.2,0.2);
        pts[1] = Points(0.4,0.2);
        pts[2] = Points(0.4,0.4);
        pts[3] = Points(0.2,0.4);
    };
    
    // draw function
    void Square::draw(Square *sqr)
    {
        // draw square fill
        int i;
        glColor3f(0.2, 0.2, 0.2);
        glBegin(GL_QUADS);
        for (i = 0; i < 4; ++i)
        {
            glVertex2f(sqr->pts[i].x, sqr->pts[i].y);
        }
        glEnd();
        // draw square points
        i = 0;
    
        glColor3f(1.0, 1.0, 1.0);
        glBegin(GL_POINTS);
        for (i = 0; i < 4; ++i)
        {
            glVertex2f(sqr->pts[i].x, sqr->pts[i].y);
        }
        glEnd();
    }
    
    // mouse function
    Points Square::mouse(int x, int y)
    {
        int windowWidth = 400, windowHeight = 400;
        return Points(float(x)/windowWidth, 1.0 - float(y)/windowHeight);
    }
    
    // drag function
    Square* Square::drag(Square *sqr, Points *mouse)
    {
        sqr->pts[0].x = mouse->x - 0.1;
        sqr->pts[0].y = mouse->y - 0.1;
        sqr->pts[1].x = mouse->x + 0.1;
        sqr->pts[1].y = mouse->y - 0.1;
    
        sqr->pts[3].x = mouse->x - 0.1;
        sqr->pts[3].y = mouse->y + 0.1;
    
        sqr->pts[2].x = mouse->x + 0.1;
        sqr->pts[2].y = mouse->y + 0.1;
    
        return sqr;
    }
    
    // GLOBAL
    
    // create square object
    Square* sqr = new Square;
    
    
    // display at start
    void display() {
        glClear(GL_COLOR_BUFFER_BIT);
        sqr->draw(sqr);
        glFlush();
    }
    
    // drag function
    void drag (int x, int y)
    {
        // int x and y of mouse converts to screen coordinates
        // returns the point as mousePt
        Points mousePt = sqr->mouse(x,y);
        //create pointer to window point coordinates
        Points* mouse = &mousePt;
    
        // if the mouse is within the square
        if (mouse->x > sqr->pts[0].x && mouse->y > sqr->pts[0].y)
        {       
            if (mouse->x < sqr->pts[2].x && mouse->y < sqr->pts[2].y)
            {
                // then drag by chaning square coordinates relative to mouse
                sqr->drag(sqr,mouse);
                glutPostRedisplay();
            }
        }
    }
    
    
    void Initialize() {
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
    }
    
    int main(int iArgc, char** cppArgv) {
    
        glutInit(&iArgc, cppArgv);
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
        glutInitWindowSize(400, 400);
        glutInitWindowPosition(200, 200);
        glutCreateWindow("Move Box");
    
    
        glutMotionFunc(drag);
    
        Initialize();
        glutDisplayFunc(display);
        glutMainLoop();
        return 0;
    }
    

答案 1 :(得分:4)

OpenGL只关注绘图过程。其他所有内容(鼠标输入,对象拾取,场景管理/更改等)完全取决于您实施。

这是一个粗略的概述:

  1. 安装鼠标单击事件处理程序(使用的确切方法取决于使用的框架和/或操作系统)

  2. 在鼠标单击事件处理程序中执行拾取操作。这通常涉及将鼠标窗口位置未投影到世界空间(请参阅gluUnproject),从而产生光线。如果它与光线相交,则测试场景中的每个对象;你必须自己实现这个,因为OpenGL只是绘制东西(在OpenGL中没有“场景”这样的东西)。

  3. 如果已选择某个对象,请将其注册为在鼠标拖动处理程序中进行操作

  4. 每当鼠标拖动事件发生时,调整对象的位置数据和OpenGL显示的触发器(你总是在OpenGL中重绘整个事物)。

  5. 释放鼠标时,从拖动处理程序中取消注册对象。

答案 2 :(得分:0)

正如其他人所说,OpenGL不处理用户输入。你想为它使用一个库。如果你想要一个更全面的解决方案,你甚至可以使用更完整的渲染或物理引擎。

对于简单的用户输入,您可以使用SDL(例如this用于鼠标输入。)

要获得更完整的2D内容,您只需使用Box2D即可。 Here是一大堆教程。

重量级解决方案是一个完整的渲染引擎,例如Ogre3DCrystalSpace

答案 3 :(得分:0)

正如其他人所说,你需要一个鼠标处理程序来获得鼠标位置。然后你需要一种方法来挑选一个物体。您有几个选项可以在OpenGL中进行选择。

  1. 如果您使用的是经典OpenGL,则可以使用选择缓冲区。以下链接是一个很好的教程 http://www.lighthouse3d.com/opengl/picking/index.php3?openglway
  2. 如果您使用的是基于着色器的现代opengl,则可以使用基于FBO的拾取。 http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html
  3. 在这两种情况下,您都可以自行实施光线跟踪选择。 gluUnproject可以在实现中提供很多帮助。 http://schabby.de/picking-opengl-ray-tracing/
  4. 之后,您只需根据鼠标移动或加速度更新对象位置。

相关问题