How to use mouse to change OpenGL camera

情到浓时终转凉″ 提交于 2019-12-23 20:01:02

问题


I'm trying to set up a camera in OpenGL to view some points in 3 dimensions. To achieve this, I don't want to use the old, fixed functionality style (glMatrixMode(), glTranslate, etc.) but rather set up the Model View Projection matrix myself and use it in my vertex shader. An orthographic projection is sufficient.

A lot of tutorials on this seem to use the glm library for this, but since I'm completely new to OpenGL, I'd like to learn it the right way and afterwards use some third party libraries. Additionally, most tutorials don't describe how to use the glMotionFunc() and glMouseFunc() to position the camera in space.

So, I guess I'm looking for some sample code and guidance how to see my points in 3D. Here's the vertex shader I've written:

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

I set up the initial value of the MVP to be the identity matrix in my shader set up method which gives me the correct 2D representation of my points:

// 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);

Now my question is how to adapt the two functions "motion" and "mouse", which to this point only have some code from a previous example, where the deprecated style of doing this was used:

// 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:


I'd like to learn it the right way and afterwards use some third party libraries.

There's nothing wrong in using GLM, as GLM is just a math library to deal with matrices. It's a very good thing that you want to learn the very basics. A trait only seldomly seen these days. Knowing these things is invaluable when doing advanced OpenGL.

Okay, three things to learn for you:

  1. Basic discrete linear algebra, i.e. how to deal with matrices and vectors with discrete elements. Scalar and complex elements will suffice for the time being.

  2. A little bit of numerics. You must be able to write code performing the elementary linear algebra operations: Scaling, and adding vectors, performing an inner and and outer product of vectors. Perform matrix-vector and matrix-matrix multiplication. Inverting a matrix.

  3. Learn about homogenous coordinates.

( 4. if you want to spice things up, learn quaternions, those things rock! )

After Step 3 you're ready to write your own linear math code. Even if you don't know about homogenous coordinates yet. Just write it do deal efficiently with matrices of dimension 4×4 and vectors of dimension 4.

Once you mastered homogenous coordinates you understand what OpenGL actually does. And then: Drop those first coding steps in writing your own linear math library. Why? Because it will be full of bugs. The one small linmath.h I maintain is riddled with them; everytime I use it in a new project I fix a number of them. Hence I recommend you use something well tested, like GLM, or Eigen.

I set up the initial value of the MVP to be the identity matrix in my shader set up method which gives me the correct 2D representation of my points:

You should separate these into 3 matrices: Model, View and Projection. In your shader you should have two, Modelview and Projection. I.e. you pass the projection to the shader as it is, but calculate a compound Model · View = Modelview matrix passed in a separate uniform.

To move the "camera" you modify the View matrix.

Now my question is how to adapt the two functions "motion" and "mouse", which to this point only have some code from a previous example, where the deprecated style of doing this was used:

Most of this code remains the same, as it doesn't touch OpenGL. What you have to replace is those glRotate and glTranslate calls.

You're working on the View matrix, as already told. First lets look what glRotate does. In fixed function OpenGL there's an internal alias, let's call it M, that is set to whatever matrix is selected with glMatrixMode. Then we can write glRotate in pseudocode as

proc glRotate(angle, vec_x, vec_y, vec_z):
    mat4x4 R = make_rotation_matrix(angle, vec_x, vec_y, vec_z)
    M = M · R

Okay, all the magic seems to lie within the function make_rotation_matrix. How that that one look. Well since you're learning linear algebra this is a great exercise for you. Find the matrix R with the following properties:

l a = R·a, where a is the axis of rotation

cos(phi) = b·c && b·a = 0 && b·c = 0, where phi is the angle of rotation

Since you probably just want to get this thing done, you can as well resort to look into the OpenGL-1.1 specification, which documents this matrix in its section about glRotatef

Right beside them you can find the specs for all the other matrix manipulation functions.

Now instead of operating on some hidden state variable you select with glMatrixMode you let your matrix math library operate directly on the matrix variable you define and supply. In your case View. And similar you do with Projection and Model. Then when you're rendering, you contract Model and View into the compound already mentioned. The reason for this is, that often you want the intermediate result of bringing the vertex position into eyespace (Modelview * position for the fragment shader). After determining the matrix values you bind the program (glUseProgram) and set the uniform values, then render your geometry. (glDraw…)



来源:https://stackoverflow.com/questions/14172331/how-to-use-mouse-to-change-opengl-camera

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!