在OpenGL/GLUT中拖动对象

5

我整天都在搜索一个简单程序的教程或示例代码 - 单击对象(例如2D矩形),然后当您按住并移动鼠标时,对象将跟随鼠标移动,然后在释放鼠标后,对象保持在新位置。换句话说,我想了解如何使用鼠标事件拖放对象。

有人能帮忙指出任何与此问题相关的有用信息来源吗?


https://dev59.com/C3jZa4cB1Zd3GeqPkPVo - Ciro Santilli OurBigBook.com
4个回答

9
感谢之前的所有回复。我已经找到了解决方法,现在我来回答我的问题。
我正在使用GLUT作为鼠标处理程序:
  1. 当鼠标被点击并移动(glutMotionFunc),会调用拖拽函数。
  2. 在拖拽功能中,鼠标坐标(x,y)被转换为Points结构,同时被转换为窗口坐标。
  3. 如果鼠标在正方形内,则通过更改其坐标和重新显示来拖动该正方形。
我仍然是OpenGL和C++的新手,因此对于代码的混乱表示歉意。我有点沮丧,因为重绘的正方形使得光标似乎捕捉到中心。我欢迎解决这个问题的替代方案以及对我的代码进行批评,以便学习。
代码(包括glut和using namespace 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;
}

5

OpenGL 仅涉及绘图过程,其它方面的功能(如鼠标输入、对象选取、场景管理和修改等)完全由您自己实现。

以下是大致的概述:

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

  2. 在鼠标单击事件处理程序中执行选取操作。这通常涉及将鼠标窗口位置映射到世界空间中(请参阅 gluUnproject),得到一条射线。测试场景中的每个对象是否与射线相交;因为 OpenGL 只绘制物体(OpenGL 中没有“场景”之类的东西),所以您必须自己实现此操作。

  3. 如果选择了一个对象,则在鼠标拖动处理程序中注册该对象以进行操作。

  4. 每次发生鼠标拖动事件时,调整对象的位置数据并触发 OpenGL 显示(在 OpenGL 中您总是重新绘制整个场景)。

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


感谢您的指导。我想我将使用GLUT来处理事件。看起来这个问题比我想象的要复杂一些。 - sebjwallace

0

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

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

对于更完整的 2D 内容,您可以直接使用 Box2D这里有很多教程。

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


0
如其他人所述,您需要获取鼠标处理程序来首先获取鼠标位置。然后,您需要一种选择对象的方法。在OpenGL中,有几种选取选项。
  1. 如果您正在使用经典的OpenGL,则可以使用选择缓冲区。以下链接是一个很好的教程 http://www.lighthouse3d.com/opengl/picking/index.php3?openglway
  2. 如果您正在使用基于着色器的现代OpenGL,则可以使用FBO based picking。 http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html
  3. 在这两种情况下,您始终可以自己实现射线跟踪选择。 gluUnproject可以在实现中提供很大的帮助。 http://schabby.de/picking-opengl-ray-tracing/
之后,您只需要根据鼠标移动或加速度更新对象位置即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接