您的位置:时时app平台注册网站 > 时时app平台注册网站 > opengl学习——录像机时时app平台注册网站

opengl学习——录像机时时app平台注册网站

2019-09-19 22:16

0.1. 资料

泡泡机器人

github example

opengl中摄像机的位置,观察的方向

gluLookAt函数

时时app平台注册网站 1

part_theta是(旋转角度/每1单位移动距离)

0.2. 使用说明

使用这个gluLookAt矩阵坐标观察矩阵可以很高效地把所有世界坐标变换为观察坐标LookAt矩阵

find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})

target_link_libraries(pangolin_test ${Pangolin_LIBRARIES})

Github 下有个example有一些例子,简单的参照着写,复杂的估计需要查opengl.

opengl中支持使用编写的uvn视景矩阵。

0.3. HelloPangolin

#include <iostream>
#include <pangolin/pangolin.h>

int main(int argc, char **argv)
{
    //创建一个窗口
    pangolin::CreateWindowAndBind("Main",640,480);
    //启动深度测试
    glEnable(GL_DEPTH_TEST);

    // Define Projection and initial ModelView matrix
    pangolin::OpenGlRenderState s_cam(
            pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
            //对应的是gluLookAt,摄像机位置,参考点位置,up vector(上向量)
            pangolin::ModelViewLookAt(0,-10,0.1,0,0,0,pangolin::AxisNegY)
    );

    // Create Interactive View in window
    pangolin::Handler3D handler(s_cam);
    //setBounds 跟opengl的viewport 有关
    //看SimpleDisplay中边界的设置就知道
    pangolin::View &d_cam = pangolin::CreateDisplay().SetBounds(0.0,1.0,0.0,1.0,-640.0f/480.0f)
                            .SetHandler(&handler);

    while(!pangolin::ShouldQuit())
    {
        // Clear screen and activate view to render into
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);

        // Render OpenGL Cube
//        pangolin::glDrawColouredCube();
        //坐标轴的创建
        pangolin::glDrawAxis(3);

        //点的创建
        glPointSize(10.0f);
        glBegin(GL_POINTS);
        glColor3f(1.0,1.0,1.0);
        glVertex3f(0.0f,0.0f,0.0f);
        glVertex3f(1,0,0);
        glVertex3f(0,2,0);
        glEnd();

        //把下面的点都做一次旋转变换
        glPushMatrix();
        //col major
        std::vector<GLfloat > Twc = {1,0,0,0, 0,1,0,0 , 0,0,1,0 ,0,0,5,1};
        glMultMatrixf(Twc.data());

        //直线的创建
        const float w = 2;
        const float h = w*0.75;
        const float z = w*0.6;
        glLineWidth(2);
        glColor3f(1.0,0,0);
        glBegin(GL_LINES);

        glVertex3f(0,0,0);
        glVertex3f(w,h,z);
        glVertex3f(0,0,0);
        glVertex3f(w,-h,z);
        glVertex3f(0,0,0);
        glVertex3f(-w,-h,z);
        glVertex3f(0,0,0);
        glVertex3f(-w,h,z);
        glVertex3f(w,h,z);
        glVertex3f(-w,h,z);
        glVertex3f(-w,h,z);
        glVertex3f(-w,-h,z);
        glVertex3f(-w,-h,z);
        glVertex3f(w,-h,z);
        glVertex3f(w,-h,z);
        glVertex3f(w,h,z);
        glEnd();

        glPopMatrix();

        // Swap frames and Process Events
        pangolin::FinishFrame();
    }

    return 0;

}

首先要确定有多少种旋转方式,

0.4. Plot data with ros

参照SimplePlot, !pangolin::ShouldQuit()换成ros::ok(),就可以

参照SimpleDisplay, 可以做出选项配置

RotateY()是竖直方向旋转

cross()是叉乘函数,即求出两个不平行向量决定的平面的(法向量)。

void setCamera(float eyex, float eyey, float eyez,
                   float centerx, float centery, float centerz,
                   float upx, float upy, float upz) 
    {
        eye.set(eyex, eyey, eyez);
        center.set(centerx, centery, centerz);
        up.setV(upx, upy, upz);

        n.setV(center, eye);
        n.normalize();
        u = n.cross(up);
        u.normalize();
        v = u.cross(n);
        v.normalize();

        R = eye.getDist();

        setModeViewMatrix();
    }

变量说明:

然后是键盘操作函数

好了,然后我们可以看看效果,可以发现和gluLookAt()没有明显的差异

然后是矩阵设置

(透视投影)符合人们心理习惯,近大远小

    glutMouseFunc(onMouse);
    glutMotionFunc(onMouseMove);

参数reshape()是函数名,接下来是reshape()函数

函数说明:

RotateRoll()是摄像机自身的旋转,n不变,旋转u和v,即roll

 或者我写的数学基础知识03

2.矩阵替换

void RotateX(float x_move)
{
    float part_theta = 30;
    float theta = x_move*part_theta*3.14/180;
    cam.yaw(theta);
}

void RotateY(float y_move)
{
    float part_theta = 30;
    float theta = y_move*part_theta*3.14 / 180;
    cam.pitch(theta);
    /*
    theta = theta / cnt;
    for (; cnt != 0; cnt--) {
        cam.pitch(theta);
    }*/
}

void RotateRoll(float x_move)
{
    float part_theta = 30;
    float theta = x_move*part_theta*3.14 / 180;
    cam.roll(theta);
}

 

RotateX()是水平方向旋转

 

 

center这个点必须是(0, 0, 0);

normalize()是规范化函数,即令向量的模变为1

109和110就是某两个按键的码,大家可以通过printf找出另外2个键来使用

这两个函数,都添加了修改摄像机的点再世界坐标系下的坐标

void onMouse(int button, int state, int x, int y)
{
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
        LeftMouseOn = true;
        x11 = x;
        y11 = y;
    }
    else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
        RightMouseOn = true;
        x11 = x;
        y11 = y;
    }
    else {
        LeftMouseOn = false;
        RightMouseOn = false;
    }
}

根据gluLookAt()的9个参数,我们同样可以计算出对应的uvn坐标系

具体说明可以参考这位大佬的文章

 

3.摄像机旋转

函数说明:

x11,y11是鼠标按下去的时候,从屏幕获得的点坐标

 

虽然可以通过reshape()来重新定视角,但是每次运行程序,只能显示一个视角,多麻烦啊。

而gluLookAt()函数,其实你可以理解成摄像机,

数据说明:

所以以下的说明都是基于(透视投影)的。 ps:其实我还不懂平行投影

放大缩小的原理,我是用摄像机和视点距离的远近变化来理解的。

首先main函数中添加

eye是世界坐标系的点,坐标系变换涉及到了平移,所以必须保存下来。

dot()是点乘函数

第一个想做的就是解决摄像机问题,让我们可以通过鼠标键盘交互,实现360度旋转和放大缩小。

重点说明:

 

和上面的大佬们的鼠标交互代码实现不一样,本人没有使用slide

这个通过opengl库中的api函数gluCylinder()就可以显示出来,但是极其蛋疼的是,完全看不出它是一个圆柱啊

刚开始学习opengl,做的第一个实验,就是显示圆柱体

如果不是(0,0,0),后面旋转函数要做相对应的修改

 

    glutReshapeFunc(reshape);

前3个参数是你的眼睛,中间3个参数是你看着的地方,最后3个参数是你的相机的正上方

所以我实现的这个函数,与其说摄像机放大缩小,还不如说是你拿着摄像机向视点走过去。(因为近大远小嘛)

  1. 使用透视投影

这里的水平和竖直指的是屏幕的水平和竖直,不是内部物体的

创建一个Point类(点),创建一个Vector类(向量),创建一个Camera类(摄像机)

不一样,因为向量是有方向的,方向有所改变,所以,一定要注意喔。

void onMouseMove(int x, int y)
{
    int dx = x - x11;
    int dy = y - y11;
//    int cnt = 10000;
    if (LeftMouseOn == true) {
        RotateX(dx);
        RotateY(dy);
    }
    else if (RightMouseOn == true) {
        RotateRoll(dx);
    }
    x11 = x;
    y11 = y;
    //x11 = x21;
    //y11 = y21;
}

只要鼠标在移动,都要修改当前鼠标的坐标,

数学基础知识03

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0, 1, 0);
}

参数说明:

举个例子,你把摄像机往上移动,如果你的眼睛不跟上的摄像机,你能看见东西吗?

最终目的是使uvn两两垂直。

然后由(摄像机坐标系)来解释(世界坐标系)中物体的坐标。

首先是键盘交互函数

 

以下是我修改后的yaw()函数和pitch()函数

opengl中的投影有两种,一个是(平行投影),一个是(透视投影)

举个例子:你从起点出发,向右跑出去了,但是如果你突然向左,你算是向左吗,不会,相对于起点,你还是向右的。

具体函数实现

4.摄像机放大缩小(伪)

glutKeyboardFunc(keyboard);

 

以下网址

这里的矩阵为什么出现负号,和

 

再次提醒:每次坐标系变换(无论是旋转还是平移),都要重新设置视景矩阵

 

R是视点中心到摄像机的距离,

鼠标交互函数

根据查找的资料,可以分为roll,yaw,pitch,具体说明,可以参考大佬的文章

函数说明:

void setModeViewMatrix() {
        Vector pointV(eye.x, eye.y, eye.z);
        M[0] = u.x; M[1] = v.x; M[2] = -n.x; M[3] = 0;
        M[4] = u.y; M[5] = v.y; M[6] = -n.y; M[7] = 0;
        M[8] = u.z; M[9] = v.z; M[10] = -n.z; M[11] = 0;
        M[12] = -pointV.dot(u);
        M[13] = -pointV.dot(v);
        M[14] = pointV.dot(n);
        M[15] = 1;

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
//        gluLookAt(5.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0, 1, 0);
//        gluLookAt(eye.x, eye.y, eye.z, 0.0, 0.0, 0.0, up.x, up.y, up.z);

        glMultMatrixf(M);  //这句话就是把矩阵M设为视景矩阵
    }

然后是鼠标移动的相关函数

 

 

个人理解,gluLookAt()定义了一个视景矩阵,把(世界坐标系)转换成(摄像机坐标系),

 

void keyboard(unsigned char key, int x, int y)
{
    if (key == 109){
        cam.bsChange(1);
    }
    else if (key == 110){
        cam.bsChange(-1);
    }
}

void bsChange(int d)
    {
        if (d > 0){
            R--;
            eye.set(-R*n.x, -R*n.y, -R*n.z);
        }
        else{
            R  ;
            eye.set(-R*n.x, -R*n.y, -R*n.z);
        }

        setModeViewMatrix();
    }

事先说明,这个摄像机是以世界坐标系(0, 0, 0)为中心来360度移动的,所以如果变换了中心,之后的函数都要做相对应的修改。

具体转换说明,可以参考

 

void yaw(float angle) {
        float cs = cos(angle*PI / 180);
        float sn = sin(angle*PI / 180);
        Vector t(n);
        Vector s(u);
        n.setV(cs*t.x - sn*s.x, cs*t.y - sn*s.y, cs*t.z - sn*s.z);
        u.setV(sn*t.x   cs*s.x, sn*t.y   cs*s.y, sn*t.z   cs*s.z);

        eye.set(-R*n.x, -R*n.y, -R*n.z);

        setModeViewMatrix();
    }

void pitch(float angle) {
        float cs = cos(angle*PI / 180);
        float sn = sin(angle*PI / 180);
        Vector t(v);
        Vector s(n);
        v.setV(cs*t.x - sn*s.x, cs*t.y - sn*s.y, cs*t.z - sn*s.z);
        n.setV(sn*t.x   cs*s.x, sn*t.y   cs*s.y, sn*t.z   cs*s.z);

        eye.set(-R*n.x, -R*n.y, -R*n.z);

        setModeViewMatrix();
    }

 

本文由时时app平台注册网站发布于时时app平台注册网站,转载请注明出处:opengl学习——录像机时时app平台注册网站

关键词: