鼠标拖动OpenGL/GLUT中的对象
Mouse-drag object in OpenGL/GLUT
我一整天都在搜索一个简单程序的教程或示例代码-点击对象(例如2D矩形),然后按住并移动鼠标,对象跟随鼠标,然后释放鼠标,对象保持在新位置。换句话说,我想了解如何使用鼠标事件拖放对象。
有人能帮我指出与这个问题有关的任何有用信息来源的正确方向吗?
感谢迄今为止的所有回复。
我已经想好了怎么做,所以我会继续回答我自己的问题。
我使用GLUT作为鼠标处理程序:
-
单击鼠标并移动(glutMotionFunc)时,将调用拖动函数。
-
在拖动函数中,鼠标坐标(x,y)在转换为窗口坐标时会转换为Points结构。
-
如果鼠标在正方形内,则通过更改其坐标拖动正方形并重新显示。
我对OpenGL和C++还很陌生,所以我对混乱的编码表示歉意。这样做我有点沮丧,因为重新绘制的正方形使光标看起来像是捕捉到了中心。出于学习目的,我欢迎对这个问题的替代解决方案和对我的代码的批评。
CODE(包括glut和使用命名空间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;
}
这里有一个粗略的概述:
安装鼠标点击事件处理程序(使用的确切方法取决于使用的框架和/或操作系统)
在鼠标单击事件处理程序中执行拾取操作。这通常涉及将鼠标窗口位置取消投影到世界空间中(请参见gluUnproject),从而产生光线。如果场景中的每个对象与光线相交,请对其进行测试;您必须自己实现这一点,因为OpenGL只是绘制东西(在OpenGL中并没有"场景"这样的东西)。
如果已拾取对象,则在鼠标拖动处理程序中注册该对象以进行操作
每次鼠标拖动事件发生时,调整对象的位置数据和OpenGL显示的触发器(您总是在OpenGL中重新绘制整个对象)。
释放鼠标后,从拖动处理程序中注销对象。
正如其他人所提到的,OpenGL不处理用户输入。你想用一个图书馆来做这件事。如果您想要更全面的解决方案,甚至可以使用更完整的渲染或物理引擎。
对于简单的用户输入,您可以使用SDL(例如,这是用于鼠标输入)。
对于更完整的2D内容,您可以使用Box2D。这里有一大堆教程。
重量级解决方案是一个完整的渲染引擎,如Ogre3D或CrystalSpace。
正如其他人所提到的,您需要获得一个鼠标处理程序来首先获取鼠标位置。然后你需要一种方法来挑选一个对象。您有几个选项可以在OpenGL中进行拾取。
- 如果使用的是经典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/
之后,您只需要根据鼠标的移动或加速度来更新对象的位置。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 将对象数组的引用传递给函数
- 你能重载对象变量名本身返回的内容吗
- C++使用整数的压缩数组初始化对象
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 将对象移动到std::shared_ptr
- 代理对象的常量正确性
- 提升 ASIO 无法识别计时器对象
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 如何返回一个类的两个对象相加的结果
- 使用std::函数映射对象方法
- C++ GLUT 使对象在视口外消失
- 无法在openGL和GLUT中为我想要的确切对象设置动画
- 鼠标拖动OpenGL/GLUT中的对象
- 摆脱在Qt QGlWidget中绘制实体对象的glut函数
- 在Open GL Glut中绘制一个对象数组