C++ OpenGL/GLUT 中的鼠标拖动对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20288861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mouse-drag object in OpenGL/GLUT
提问by sebjwallace
I have been searching all day for a tutorial or example code for a simple program - click on object (like a 2d rectangle for example) then as you hold and move the mouse the object follows the mouse, then on mouse release the object remains in new location. In other words, I want to understand how to drag and drop an object with the mouse events.
我一整天都在寻找一个简单程序的教程或示例代码 - 单击对象(例如 2d 矩形),然后当您按住并移动鼠标时,对象跟随鼠标,然后在鼠标释放时对象保持在新位置。换句话说,我想了解如何使用鼠标事件拖放对象。
Could anyone help to point me in the right direction of any useful sources of information relating to this problem?
任何人都可以帮助我指出与此问题相关的任何有用信息来源的正确方向吗?
回答by sebjwallace
Thanks for all the responses so far.
感谢您到目前为止的所有回复。
I have worked out how to do it, so I will go ahead an answer my own question.
我已经弄清楚了如何去做,所以我将继续回答我自己的问题。
I am using GLUT as a mouse handler:
我使用 GLUT 作为鼠标处理程序:
When the mouse is clicked and moving (glutMotionFunc) the drag function is called.
In the drag function the mouse coordinates (x,y) are converted to a Points struct while being converted into window coordinates.
If the mouse is within the square then drag the square by changing it's coordinates and redisplay.
当鼠标被点击并移动 (glutMotionFunc) 时,会调用拖动函数。
在拖动函数中,鼠标坐标 (x,y) 被转换为 Points 结构,同时被转换为窗口坐标。
如果鼠标在正方形内,则通过更改其坐标并重新显示来拖动正方形。
I am still very new to OpenGL and C++ so I do apologize for the messy coding. I am a bit frustrated in doing it this way as the redrawn square makes it seem the cursor snaps to the center. I welcome alternative solutions to this problem and criticism of my code, for learning purposes.
我对 OpenGL 和 C++ 还是很陌生,所以我为混乱的编码道歉。这样做让我有点沮丧,因为重新绘制的正方形使光标看起来好像捕捉到了中心。我欢迎这个问题的替代解决方案和对我的代码的批评,以供学习之用。
CODE (included glut and using namespace std):
代码(包括 glut 和 using 命名空间 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;
}
回答by datenwolf
OpenGL is only concerned with the drawing process. Everything else (mouse input, object picking, scene management/alterations, etc.) is completely up to you to implement.
OpenGL 只关心绘图过程。其他一切(鼠标输入、对象拾取、场景管理/更改等)完全由您来实现。
Here's a rough outline:
这是一个粗略的概述:
Install a mouse click event handler (the exact method to use depends on the framework used and/or the operating system)
In the mouse click event handler perform a picking operation. This usually involves unprojecting the mouse window position into the world space (see gluUnproject) resulting in a ray. Test each object in the scene if it intersects with the ray; you'll have to implement this yourself, because OpenGL just draws thing (there is no such thing as a "scene" in OpenGL).
If a object has been picked register it to be manipulated in the mouse drag handler
everytime a mouse drag event happens adjust the object's position data and trigger of the OpenGL display (you always redraw the whole thing in OpenGL).
When the mouse is released unregister the object from the drag handler.
安装鼠标单击事件处理程序(使用的确切方法取决于使用的框架和/或操作系统)
在鼠标单击事件处理程序中执行拾取操作。这通常涉及将鼠标窗口位置取消投影到世界空间(参见 gluUnproject),从而产生一条射线。测试场景中的每个对象是否与射线相交;您必须自己实现这一点,因为 OpenGL 只是绘制东西(OpenGL 中没有“场景”这样的东西)。
如果一个对象已被拾取,则将其注册为在鼠标拖动处理程序中进行操作
每次发生鼠标拖动事件时,调整对象的位置数据和 OpenGL 显示的触发器(您总是在 OpenGL 中重绘整个事物)。
当鼠标被释放时,从拖动处理程序中取消注册对象。
回答by Domi
As mentioned by others, OpenGL does not handle user input. You want to use a library for that. If you want a more all-around solution, you can even use a more complete render or physics engine.
正如其他人所提到的,OpenGL 不处理用户输入。你想为此使用一个库。如果您想要更全面的解决方案,您甚至可以使用更完整的渲染或物理引擎。
For simple user input, you can use SDL(e.g. thisis for mouse input).
对于简单的用户输入,您可以使用SDL(例如,这是用于鼠标输入)。
For more complete 2D stuff, you can just use Box2D. Hereare a whole bunch of tutorials.
对于更完整的 2D 内容,您可以使用Box2D。这里有一大堆教程。
The heavy-weight solution is a complete render engine, such as Ogre3Dor CrystalSpace.
重量级的解决方案是一个完整的渲染引擎,例如Ogre3D或CrystalSpace。
回答by sirian_ye
As mentioned by others, you need to get a mouse handler to get the mouse position first. Then you need a way to pick an object. You have a few options to do the picking in OpenGL.
正如其他人所提到的,您需要先获得一个鼠标处理程序才能获得鼠标位置。然后你需要一种方法来选择一个对象。您有几个选项可以在 OpenGL 中进行选择。
- If you are using classic OpenGL, you can use the select buffer. The following link is a good tutorial http://www.lighthouse3d.com/opengl/picking/index.php3?openglway
- If you are using modern opengl, which is shader based, you can use FBO based picking. http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html
- You can always implement a ray tracking picking yourself in both cases. The gluUnproject can help a lot in the implementation. http://schabby.de/picking-opengl-ray-tracing/
- 如果您使用的是经典 OpenGL,则可以使用选择缓冲区。以下链接是一个很好的教程 http://www.lighthouse3d.com/opengl/picking/index.php3?openglway
- 如果您使用的是基于着色器的现代 opengl,则可以使用基于 FBO 的拾取。 http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html
- 在这两种情况下,您始终可以自己实现光线跟踪拾取。gluUnproject 可以在实施中提供很多帮助。 http://schabby.de/picking-opengl-ray-tracing/
After that, you just need to update the object position according to the mouse movement or acceleration.
之后,您只需要根据鼠标移动或加速度更新对象位置。