如何使用鼠标拖动事件 OpenGL(带透视投影)添加场景平移?
How to add a scene panning using mouse drag event OpenGL( with perspective projection)?
是否可以通过简单的鼠标事件实现场景平移(有点像我们在 gmaps 中获得的效果)?目前我有两个鼠标事件:
通过在 glTranslatef
中更改 cRadius
来缩放鼠标滚轮
鼠标左键拖动旋转,在glRotatef
中改变xrot
和yrot
。
函数如下:
float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, zrot = 0, cRadius = 30.0f, lastx, lasty, lastz;
void mouseMovement(int x, int y)
{
int diffx = x - lastx;
int diffy = y - lasty;
lastx = x;
lasty = y;
xrot += (float)diffy;
yrot += (float)diffx;
}
和下面的鼠标按键初始化函数
void mouseFunc(int button, int state, int x, int y)
{
lastx = x;
lasty = y;
}
是否可以使用与旋转相同的逻辑来启用平移功能,例如替换 xrot
和 yrot
在 glTranslatef
中有不同的变量(如果不是应该在哪里应用翻译)?下面是我的显示功能以及重塑功能。我正在使用 glPerspective
而不是 glLookat
void display(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -cRadius);
glRotatef(xrot, 1.0, 0.0, 0.0);
glRotatef(yrot, 0.0, 1.0, 0.0);
glBegin(GL_LINES);
------------
------
glTranslated(-xpos, 0.0f, zpos);
glutSwapBuffers();
glEnd();
}
鼠标函数已在主循环中调用
int OpenGL(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Window");
glutDisplayFunc(display);
glutIdleFunc(display);
glutMouseFunc(mouseFunc);
glutMotionFunc(mouseMovement);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
//整形
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)w / (GLfloat)h, 0.1, 500.0);
glMatrixMode(GL_MODELVIEW);
}
透视投影平移取决于对象的深度。 (参见 。
幸运的是你了解几何学。它在视图 space 中由 cRadius
定义。
视图中的投影区域 space 与视图的 Z 坐标 space 之间的关系是线性的。这取决于视角和纵横比。
(另请参阅 )
标准化设备 space 中的投影尺寸可以通过以下方式转换为视图 space 中的尺寸:
aspect = w / h
tanFov = tan(fov_y * 2.0) * 2.0;
size_x = ndx_size_x * z_eye * tanFov * aspect;
size_y = ndx_size_y * z_eye * tanFov;
将其应用于您的代码:
#define _USE_MATH_DEFINES
#include <math.h>
float cRadius = 10.0f;
float fov_y = 60.0f;
float nearp = 0.1f;
float farp = 500.0f;
float width = 500.0f;
float height = 500.0f;
void mouseMovement(int x, int y)
{
int diffx = x - lastx;
int diffy = y - lasty;
lastx = x;
lasty = y;
float ndc_x = diffx * 2.0f / width;
float ndc_y = diffy * 2.0f / height;
float aspect = width / height;
float fov_rad = fov_y * M_PI / 180.0;
float tanFov = tan(fov_rad / 2.0);
xtrans += ndc_x * cRadius * tanFov * aspect;
ytrans -= ndc_y * cRadius * tanFov;
}
void mouseFunc( int button, int state, int x, int y )
{
lastx = x;
lasty = y;
}
void reshape(int w, int h)
{
width = (float)w;
height = (float)h;
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov_y, width / height, nearp, farp);
glMatrixMode(GL_MODELVIEW);
}
void display(void)
{
// [...]
glLoadIdentity();
glTranslatef(xtrans, ytrans, -cRadius);
glRotatef(xrot, 1.0, 0.0, 0.0);
glRotatef(yrot, 0.0, 1.0, 0.0);
// [...]
glEnd();
glutSwapBuffers();
}
是否可以通过简单的鼠标事件实现场景平移(有点像我们在 gmaps 中获得的效果)?目前我有两个鼠标事件:
通过在
中更改glTranslatef
cRadius
来缩放鼠标滚轮鼠标左键拖动旋转,在
glRotatef
中改变xrot
和yrot
。函数如下:
float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, zrot = 0, cRadius = 30.0f, lastx, lasty, lastz;
void mouseMovement(int x, int y)
{
int diffx = x - lastx;
int diffy = y - lasty;
lastx = x;
lasty = y;
xrot += (float)diffy;
yrot += (float)diffx;
}
和下面的鼠标按键初始化函数
void mouseFunc(int button, int state, int x, int y)
{
lastx = x;
lasty = y;
}
是否可以使用与旋转相同的逻辑来启用平移功能,例如替换 xrot
和 yrot
在 glTranslatef
中有不同的变量(如果不是应该在哪里应用翻译)?下面是我的显示功能以及重塑功能。我正在使用 glPerspective
而不是 glLookat
void display(void)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -cRadius);
glRotatef(xrot, 1.0, 0.0, 0.0);
glRotatef(yrot, 0.0, 1.0, 0.0);
glBegin(GL_LINES);
------------
------
glTranslated(-xpos, 0.0f, zpos);
glutSwapBuffers();
glEnd();
}
鼠标函数已在主循环中调用
int OpenGL(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Window");
glutDisplayFunc(display);
glutIdleFunc(display);
glutMouseFunc(mouseFunc);
glutMotionFunc(mouseMovement);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
//整形
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)w / (GLfloat)h, 0.1, 500.0);
glMatrixMode(GL_MODELVIEW);
}
透视投影平移取决于对象的深度。 (参见
幸运的是你了解几何学。它在视图 space 中由 cRadius
定义。
视图中的投影区域 space 与视图的 Z 坐标 space 之间的关系是线性的。这取决于视角和纵横比。
(另请参阅
标准化设备 space 中的投影尺寸可以通过以下方式转换为视图 space 中的尺寸:
aspect = w / h
tanFov = tan(fov_y * 2.0) * 2.0;
size_x = ndx_size_x * z_eye * tanFov * aspect;
size_y = ndx_size_y * z_eye * tanFov;
将其应用于您的代码:
#define _USE_MATH_DEFINES
#include <math.h>
float cRadius = 10.0f;
float fov_y = 60.0f;
float nearp = 0.1f;
float farp = 500.0f;
float width = 500.0f;
float height = 500.0f;
void mouseMovement(int x, int y)
{
int diffx = x - lastx;
int diffy = y - lasty;
lastx = x;
lasty = y;
float ndc_x = diffx * 2.0f / width;
float ndc_y = diffy * 2.0f / height;
float aspect = width / height;
float fov_rad = fov_y * M_PI / 180.0;
float tanFov = tan(fov_rad / 2.0);
xtrans += ndc_x * cRadius * tanFov * aspect;
ytrans -= ndc_y * cRadius * tanFov;
}
void mouseFunc( int button, int state, int x, int y )
{
lastx = x;
lasty = y;
}
void reshape(int w, int h)
{
width = (float)w;
height = (float)h;
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov_y, width / height, nearp, farp);
glMatrixMode(GL_MODELVIEW);
}
void display(void)
{
// [...]
glLoadIdentity();
glTranslatef(xtrans, ytrans, -cRadius);
glRotatef(xrot, 1.0, 0.0, 0.0);
glRotatef(yrot, 0.0, 1.0, 0.0);
// [...]
glEnd();
glutSwapBuffers();
}