• 视图和模型变换


    视图变换,是指变换照相机的位置,角度。
    模型变换,是指变换被照物体的位置,角度。

    这两个变换,都会影响最终图形中,物体的位置,角度。而这两个变换,可以达到相同的效果。比如,你想要一个倒着的水杯图形,可以把你自己倒立,这样看到的水杯就是倒立的了。或者把水杯倒立,自己直立,也能看到倒立的水杯。
    这里写图片描述
    如图所示,这两种变换,可以看做达到目的的不同途径。甚至可以同时使用视图变换和模型变换,只要最终拿到了我们想要的图像就可以了。至于使用的是视图变换,还是模型变换,看我们理解问题的角度。

    3.2.1 对变换进行思考

    变换顺序,对最终的结果影响很大。
    看下面的例子:
    这里写图片描述
    图中有两个操作,旋转和移动。一个是沿原点绕z轴逆时针旋转45度,另一个是沿x轴向下平移。左图中,是先旋转,再移动,物体最终在x轴上。右图中,是先移动,再旋转,物体最终在x=y轴上。变换顺序不同,导致物体最终位置不同,这就是变换顺序的影响。

    变换顺序,在OpenGL中的具体实现。
    在OpenGL中,所有的变换,都是通过矩阵来实现的。一个矩阵,表示一个或多个变换。模型视图变换,是通过模型视图矩阵来实现的。由于这个矩阵经常变换,需要进行管理,OpenGL中是通过矩阵堆栈来对矩阵进行管理的。

    当前模型视图矩阵如果用C来表示,在当前模型视图基础上,进行一个变换,这个变换使用的矩阵为M。那么一个顶点v的变换之后的坐标为CMv。也就是说,M变换先作用于顶点v,然后再是当前模型视图矩阵C。

    看下面的例子:

    glMatrixMode(GL_MODELVIEW);
    glLoadIndentity();
    glMultMatrixf(N);       //变换N
    glMultMatrixf(M);       //变换M
    glMultMatrixf(L);       //变换L
    glBegin(GL_POINTS);
    glVertex3f(v);
    glEnd();
     

    这段代码中,模型视图矩阵按顺序分别包含了I, N, NM,最后是NML,其中I表示单位矩阵。经过变换的顶点是NMLv。因此,顶点变换就是N(M(Lv)),也就是说,v首先与L相乘,Lv再与M相乘,MLv再与N相乘,而不是按它们指定的顺序出现的。

    全局固定坐标系

    图3-4中,左图中的先旋转,再平移,代码实现如下:

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glMultMatrixf(T);   //平移
    glMultMatrixf(R);   //旋转
    draw_the_object();

    只要记住一点,物体的变换顺序,和矩阵的出现顺序,正好相反。

    局部移动坐标系统

    这个通常用于模型的关节控制。比如机器人手臂。比如画汽车轮子上的螺钉,这个螺钉的位置,相对于汽车轮子,这个轮子上建立的坐标系,叫局部移动坐标系。而轮子的位置,又是相对于汽车本身,最后,汽车本身,是在全局坐标系中指定。

    3.2.2 模型变换

    模型变换,主要涉及三个函数,移动、旋转、缩放。有了这三个函数的组合,我们可以进行任意变换。

    void glTranslate{fd}(TYPE x, TYPE y, TYPE z);
    void glRotate{fd}(TYPE angle, TYPE x, TYPE y, TYPE z);
    void glScale{fd}(TYPE x, TYPE y, TYPE z);
    这三个函数,之前接触过。glTranslate,进行平移,平移的偏移量,由(x, y, z)指定。 glRotate,旋转,以逆时针方向绕着从原点到点(x, y, z)的直线旋转角度angle。glScale,按照一定比列进行缩放,比例在x轴,y轴,z轴方向上的量是(x, y, z)。

    3.2.3 视图变换

    视图变换,相关的三个函数是glTranslate,glRotate和gluLookAt函数。

    这个glTranslate和glRotate在模型变换中,我们已经见过了。怎么模型变换和视图变换,使用的是同样的函数呢?因为变换是相对的。 比如,让模型和照相机距离5个单位长度,假设模型和照相机放在一起。我们可以将物体向前移动5个单位长度,也可以将照相机向后移动5个单位长度。所以,视 图变换,也是使用glTranslate和glRotate。只是这个参数的含义相反罢了。
    比如

    glTranslatef(0.0, 0.0, -5.0);

    这个函数在场景中把物体沿z轴移动-5个单位,相当于把照相机沿z轴移动+5个单位。

    使用工具函数gluLookAt()

    void gluLookAt(
        GLdouble eyex, GLdouble eyey, GLdouble eyez,
        GLdouble centerx, GLdouble centery, GLdouble centerz,
        GLdouble upx, GLdouble upy, GLdouble upz);
    定义一个视图矩阵,并把它与当前矩阵进行右乘。目标观察点eyex, eyey, eyez。centerx, centery和centerz参数指定了视线上的任意一点。upx,upy和upz参数表示哪个方向是朝上的(也就是说,在视景体中自底向上的方向)。

    默认情况下,照相机位于原点,指向z轴的负方向,以y轴的正方向为朝上方向。相当于调用:

    gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, -100.0, 0.0, 1.0, 0.0);
    参考点的z值是-100.0, 但它也可以是任意的负值,因为它不会影响视线的方向。

    下面是使用gluLookAt的一个例子。

    gluLookAt(4.0, 2.0, 1.0, 2.0, 4.0, -3.0, 2.0, 2.0, -1.0);

    这里写图片描述
    这个函数,将摄像机移动到了(4.0, 2.0, 1.0)这个点,摄像机朝向(2.0, 4.0, -3.0)方向,摄像机向上的方向为(2.0, 2.0, -1.0)。

    强烈推荐,理解这几个函数(glTranslate, glRotate, gluLookAt),使用Nate Robin的教程。网上有下的。

    创建自定义的工具函数

    创建自定义的函数,其实就是在自己的函数中,调用glTranslate和glRotate这两个函数。
    要创建自定义的工具函数,主要是弄清楚两个东西:一个是参数是相对于哪个坐标系的,第二个就是照相机的变换顺序,与glTranslate,glRotate出现的顺序相同。

    比如编写一个飞机模拟器,并且以飞机的驾驶员座位观察点显示飞机外面的景象。我们可以用一个圆点位于跑道上的坐标系统来描述整个场景,飞机相对于坐 标(x, y, z)。然后,假设飞机还有倾侧角、螺旋角和航向改变角(这些都是飞机相对于它的重心的旋转角度)。下面这个函数可以作用视图变换函数使用。

    void pilotView(GLdouble planex, GLdouble planey, GLdouble planez, GLdouble roll, GLdouble pitch, GLdouble heading)
    {
        glRotated(roll, 0.0, 0.0, 1.0);
        glRotated(pitch, 0.0, 1.0, 0.0);
        glRotated(heading, 1.0, 0.0, 0.0);
        glTranslated(-planex, -planey, -planez);
    }
    这个其实很好理解,因为这个roll, pitch, heading,都是相对于飞机的。而飞机,就是我们的相机。所以,先将飞机旋转到一定角度,然后移动到点(planex, planey, planez)上面。因为这个planex, planey, planez是相对于机场跑道的坐标系,而我们移动的飞机相当于相机,所以都要取负号。
  • 相关阅读:
    如何利用JMeter模拟超过 5 万的并发用户
    JQUERY插件JqueryAjaxFileUplaoder----更简单的异步文件上传
    jmeter内存溢出处理方式记录
    JMeter压力测试入门教程[图文]
    本机Tomcat启动myeclipse,用Jmeter录制脚本端口冲突解决办法
    Jmeter 录制脚本
    Jmeter基础之---jmeter基础概念
    Jmeter性能测试 入门
    SSH Secure Shell Client安装和使用
    面向对象2
  • 原文地址:https://www.cnblogs.com/zhoug2020/p/5786218.html
Copyright © 2020-2023  润新知