【问题标题】:How to add a scene panning using mouse drag event OpenGL( with perspective projection)?如何使用鼠标拖动事件 OpenGL(带透视投影)添加场景平移?
【发布时间】:2019-12-30 15:23:23
【问题描述】:

是否可以通过简单的鼠标事件进行场景平移(有点像我们在 gmaps 中获得的)?目前我有两个鼠标事件:

  1. 鼠标滚轮通过在glTranslatef中更改cRadius来缩放

  2. 通过更改glRotatef 中的xrotyrot 来拖动LMB。

    下面是函数:

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;
}

是否可以使用与旋转相同的逻辑来启用平移功能,例如用 @987654331 中的不同变量替换 xrotyrot @(如果不是应该在哪里应用翻译)?下面是我的显示功能和重塑功能。我使用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);
}

【问题讨论】:

  • 透视投影平移取决于对象的深度。相关:Qmatrix4x4 translate does not take any effect
  • 我浏览了链接,但我不知道如何在我的代码中实现它。如您所见,我当前的鼠标功能没有定义任何按钮或状态(GLUT_UP 或 GLUT_DOWN)。到目前为止,我的 LMB 和 RMB 都在做同样的事情。 gltranslatef 可以根据鼠标进行更改吗?通过更改 gltranslatef 中的 cRadius(在显示下),我使用 glutMouseWheelFunc 的“缩放”相同

标签: opengl visual-c++ glut freeglut glu


【解决方案1】:

在透视投影中,平移取决于对象的深度。 (见Qmatrix4x4 translate does not take any effect
幸运的是,您了解几何学。它由cRadius 在视图空间中定义。

视图空间中的投影面积与视图空间的Z坐标之间的关系是线性的。这取决于视场角和纵横比。
(另见Field of view + Aspect Ratio + View Matrix from Projection Matrix (HMD OST Calibration)

标准化设备空间中的投影尺寸可以通过以下方式转换为视图空间中的尺寸:

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();
}

【讨论】:

  • 完美运行!我还添加了一个 if else 语句来检查 mouseFunc 和 mouseMovement 中的左键或右键单击。现在我已经配置了所有鼠标按钮。 LMB 用于旋转,RMB 用于平移,鼠标滚轮用于缩放。再次感谢!!
猜你喜欢
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多