如何使用鼠标改变OpenGL相机

3
我正在尝试在OpenGL中设置相机来查看三维空间中的一些点。为了实现这个目标,我不想使用旧的固定功能风格(glMatrixMode()、glTranslate等),而是自己设置模型视图投影矩阵,在顶点着色器中使用它。一个正交投影就足够了。
很多关于这方面的教程似乎都使用glm库进行,但由于我完全不懂OpenGL,我想学习正确的方式,然后再使用第三方库。此外,大多数教程都没有描述如何使用glMotionFunc()和glMouseFunc()将相机放置在空间中。
因此,我想找一些示例代码和指导,以便在3D中查看我的点。这里是我编写的顶点着色器:
const GLchar *vertex_shader =   // Vertex Shader
"#version 330\n"
"layout (location = 0) in vec4 in_position;"
"layout (location = 1) in vec4 in_color;"
"uniform float myPointSize;"
"uniform mat4 myMVP;"
"out vec4 color;"  
"void main()"  
"{"
"   color = in_color;"
"   gl_Position = in_position * myMVP;"
"   gl_PointSize = myPointSize;"
"}\0";

我在着色器设置方法中将MVP的初始值设置为单位矩阵,这给了我正确的点的二维表示:

// Set up initial values for uniform variables
glUseProgram(shader_program);

location_pointSize = glGetUniformLocation(shader_program, "myPointSize");
glUniform1f(location_pointSize, 25.0f);

location_mvp = glGetUniformLocation(shader_program, "myMVP");
float mvp_array[16] = {1.0f, 0.0f, 0.0f, 0.0f,  // 1st column
                       0.0f, 1.0f, 0.0f, 0.0f,  // 2nd column
                       0.0f, 0.0f, 1.0f, 0.0f,  // 3rd column
                       0.0f, 0.0f, 0.0f, 1.0f   // 4th column
                      };
glUniformMatrix4fv(location_mvp, 1, GL_FALSE, mvp_array);

glUseProgram(0);

现在我的问题是如何适应两个函数“motion”和“mouse”,到目前为止这两个函数只有一些代码来自以前的示例,其中使用了过时的方法:
// OLD, UNUSED VARIABLES
int mouse_old_x;
int mouse_old_y;
int mouse_buttons = 0;
float rotate_x = 0.0;
float rotate_y = 0.0;
float translate_z = -3.0;

...
// set view matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, translate_z);
glRotatef(rotate_x, 1.0, 0.0, 0.0);
glRotatef(rotate_y, 0.0, 1.0, 0.0);
...

// OLD, UNUSED FUNCTIONS
void mouse(int button, int state, int x, int y)
{
    if (state == GLUT_DOWN)
    {
        mouse_buttons |= 1<<button;
    }
    else if (state == GLUT_UP)
    {
        mouse_buttons = 0;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}

void motion(int x, int y)
{
    float dx, dy;
    dx = (float)(x - mouse_old_x);
    dy = (float)(y - mouse_old_y);

    if (mouse_buttons & 1)
    {
        rotate_x += dy * 0.2f;
        rotate_y += dx * 0.2f;
    }
    else if (mouse_buttons & 4)
    {
        translate_z += dy * 0.01f;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}
1个回答

6
我希望你能以正确的方式学习,然后使用一些第三方库。GLM没有问题,因为GLM只是一个处理矩阵的数学库。你想要学习基础知识是非常好的事情,在进行高级OpenGL时了解这些内容是非常宝贵的。
好的,你需要学习以下三个方面:
1. 基本的线性代数,即如何处理具有离散元素的矩阵和向量。目前只需要标量和复杂元素。 2. 了解一点数值计算。你必须编写代码来执行基本的线性代数操作:缩放和添加向量、执行向量的内积和外积、执行矩阵-向量和矩阵-矩阵乘法、求逆矩阵。 3. 学习齐次坐标。 4. 如果你想增加难度,可以学习四元数,这些东西很棒!
完成第三步后,你就可以编写自己的线性数学代码了。即使你还不了解齐次坐标,也可以编写出有效地处理4×4维矩阵和4维向量的代码。
掌握了齐次坐标后,你就能够理解OpenGL实际上在做什么了。然后,丢弃写自己的线性数学库的第一步。为什么?因为那会充满错误。我维护的一个小linmath.h文件就充满了错误;每次在新项目中使用它时,我都会修复其中的一些错误。因此,我建议你使用像GLM或Eigen这样经过充分测试的库。
你应该将其分成三个矩阵:模型、视图和投影。在着色器中,你应该有两个,即模型视图和投影。也就是说,你将投影作为一个uniform传递给着色器,但要计算一个复合的Model · View = Modelview矩阵并将其作为单独的uniform传递。
要移动"摄像机",你需要修改View矩阵。
大部分代码保持不变,因为它们没有涉及OpenGL。你需要替换的是那些glRotate和glTranslate调用。
你正在操作View矩阵,如前所述。首先让我们看看glRotate的操作。在固定函数的OpenGL中,有一个内部别名,称为M,它被设置为与glMatrixMode选择的矩阵相同。然后我们可以将glRotate写成伪代码:
proc glRotate(angle, vec_x, vec_y, vec_z):
    mat4x4 R = make_rotation_matrix(angle, vec_x, vec_y, vec_z)
    M = M · R

好的,所有的魔法似乎都在函数make_rotation_matrix中。看起来这样。既然你正在学习线性代数,这是一个很好的练习。找到具有以下属性的矩阵R

l a = R·a,其中a是旋转轴

cos(phi) = b·c && b·a = 0 && b·c = 0, 其中phi是旋转角度

由于你可能只是想完成这个任务,你可以查看OpenGL-1.1规范,该规范记录了与glRotatef部分相关的矩阵。

glRotate OpenGL-2 spec

在它们旁边,你可以找到所有其他矩阵操作功能的规范。

现在,你不用再操作一些隐藏的状态变量,而是让你的矩阵数学库直接操作你定义和提供的矩阵变量。在你的情况下是View。类似地,你也要对ProjectionModel进行操作。然后当你渲染时,将Model和View合并成已经提到的复合物。这样做的原因是,通常你希望将顶点位置带入眼空间的中间结果(片段着色器的Modelview * position)。确定矩阵值后,你绑定程序(glUseProgram)并设置统一值,然后渲染几何体(glDraw…)。


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