• Opengl编程指南第三章:视图



    1、概述

    对象的三维坐标需要经过一系列的计算才能编程屏幕上的像素:

    坐标变换:通过矩阵乘法实现,包括模型变换,视角变换,投影变换。涉及的操作有,平移、旋转、缩放、透视投影、正交投影;
    剪切:由于整个场景最终被绘制到一个矩形窗口上,位置在窗口外的图元必需被剪切掉;
    视口变换:将变换后的坐标对应到屏幕像素。

    拿照相来做比喻,照相可能需要以下几个步骤:
    1、放置好三脚架和相机(视角变换)
    2、把场景中的物体摆好位置(模型变换)
    3、调整焦距(投影变换)
    4、确定最终照片的大小(视口变换)

    所有的坐标变换是通过一个4x4的矩阵来实现的,v' = v*M。

     

    2、矩阵操作API

    glMatrixMode(GLenum mode)指定当前的矩阵,mode的值为GL_MODELVIEW, GL_PROJECTION
    glLoadIdentity()把当前矩阵重置为单位矩阵
    glLoadMatrix*(const TYPE *m)把当前矩阵置为参数指定的矩阵
    glMultMatrix*(const TYPE *m)将当前矩阵与参数矩阵想乘



    3、视角、模型变换

    视角变换和模型变换是相对的。以上一节的照相机比方为例,把物体沿某个方移动,等价于把照相机沿相反的方向移动。所以在opengl里面,这个两个变换被合成用一个矩阵表示。在考虑具体场景的时候,到底聪视角变换的角度出发,还是从模型变换的角度出发,就看哪个更加自然,更加符合你的思维习惯。

    变换的顺序
    假设一个物体中心处于原点位置,先沿Z轴逆时针旋转45度再沿X轴平移一段距离,此时物体处于X轴上;加入将这两个变换的顺序反过来,物体则处于直线y=x上。
    “一次变换”相当于当前的变换矩阵乘以一个新的变换举证。假设当前的矩阵是C,接着两个变换M,N,则最终的矩阵变为CMN。顶点v经过该矩阵的变换得到v'=CMNv=C(M(Nv)),相当于顶点依次经历变换N,M,C。由此可见,顶点实际的变换顺序和代码所写的变换顺序实际上是相反的。
    上面的分析是把物体放在一个固定的、大的坐标系中来考虑的。如果想象每个物体有一个固有的局部坐标系,所有的变换都是相对这个局部坐标系发生,那么变换的顺序就和代码一致了:移动时,物体和局部坐标系移动相对于当前局部坐标系移动,旋转时类似。


    模型变换API:glScale;glTranslate;glRotate;
    视角变换API: api相同(模型变换和视角变换是相对的),比如glScale相当于把场景中所有物体的大小进行缩放。视角变换在代码中一般处在模型变换之前,从上边的分析可以,实际上作用于模型变换之后,这是符合编程者设计场景的一般流程的。gluLookAt是辅助库的函数,通过组合上述api而实现。


    4、投影变换

    投影变换的目的是定义一个视体空间(或视见体,view volume),它决定了顶点如何被投影到屏幕上,同时决定了那些物体或物体部分应该被剪切掉。
    透视投影(Perspective Projection):透视投影的特点是远离视点的物体会显得小,而近处的物体显得大。这是因为透视投影的视见体是一个“截头椎体”(frustum),里面的物体都向视点一侧的椎体顶点投影。glFrustum(GLdouble left, GLdouble right,GLdouble bottom, GLdouble top,GLdouble near, GLdouble far)或void gluPerspective(GLdouble fovy, GLdouble aspect,GLdouble near, GLdouble far),具体解释请参考原书。
    正投影(Orthographic Projection):正投影的视见体是一个矩形体,无论近处的还是远处的物体都会平行地投影到屏幕上。API,glOrtho*。
    可见投影变换定义了6个剪切面(Clipping pane),场景的物体会被这个6个面剪切。


    5、视口变换

    视口变换定义了用户显示最终画面的窗口矩形区域。注意:此时物体已经经过视角模型变换、投影变换,经过了剪切。glViewport(GLint x, GLint y, GLsizei width, GLsizei height)。

    深度坐标
    在视口变换的过程中,深度坐标(depth(z) coordinate)会被编码。可以同通过glDepthRange设定一个范围,使z值被缩放至这个范围内。glDepthRange(GLclampd near, GLclampd far);定义depth buffer中存储的最大和最小值,默认是0,1,输入参数会被现在[0,1]以内。受透视除法(perspective division)的影响,frustum的远端的depth坐标的精度弱于近端。


    6、其他

    矩阵栈
    模型视角矩阵和投影矩阵实际上有各自的栈,你操作的是栈顶的矩阵,矩阵栈对于构建层次化、复杂对象很有用。
    glPushMatrix() 拷贝当前矩阵并推入栈顶
    glPopMatrix() 弹出栈顶矩阵


    额外的剪切面
    除了视见体所定义的六个剪切面之外,你还可以定义额外的剪切面。|
    一个面由方程Ax+By+Cz+D=0来定义。
    glClipPlane(GLenum plane, const GLdouble *equation);pane是GL_CLIP_PLANEi(i=0...),需要先调用glEnable(GL_CLIP_PLANEi)激活;*equation则是(A,B,C,D)四个变量组成的向量buffer。
    满足(A B C D)M-1(xe ye ze we)T>=0的点被保留,否则被剪切掉,(xe,ye,ze,we)是眼坐标。实际上就是向量(A,B,C)所指向的平面一侧被保留。


    逆向坐标变换
    有时,你需要逆向地进行坐标变换,比如通过鼠标在屏幕上点击一个点,如何找出与这个点对应的世界坐标系中的点呢?
    int gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
    const GLdouble modelMatrix[16],
    const GLdouble projMatrix[16],
    const GLint viewport[4],
    GLdouble *objx, GLdouble *objy, GLdouble *objz);
    winx, winy是屏幕坐标,winz则是depth坐标,也即glDepthRange定义的值;
    modelMatrix是模型视角矩阵
    projMatrix是投影矩阵
    viewport是视口范围
    objx,objy,objz存储返回的坐标值


    int gluProject(GLdouble objx, GLdouble objy, GLdouble objz,
    const GLdouble modelMatrix[16],
    const GLdouble projMatrix[16],
    const GLint viewport[4],
    GLdouble *winx, GLdouble *winy, GLdouble *winz);
    与gluUnProject相反,从世界坐标系映射到屏幕坐标系。

     

    关于变换的一些更基础知识可以参考博客:http://blog.csdn.net/popy007/#


  • 相关阅读:
    Centos7 yum缓存rpm安装包 规格严格
    基于postgresql行级锁for update测试 规格严格
    Web安全 Acunetix漏洞扫描工具.(破解版) 规格严格
    PostgreSQL 数组(Array) 规格严格
    oracle恢复broken的job,Oracle JOB异常中断原因分析 规格严格
    Eureka 与 zookeeper 的区别、原理及各自优缺点 规格严格
    Appenders 规格严格
    在windows下使用s3cmd和s3browser来管理amazon s3的笔记
    [python][flask] Flask 图片上传与下载例子(支持漂亮的拖拽上传)
    【转】评估分类模型的指标:ROC/AUC
  • 原文地址:https://www.cnblogs.com/longhuihu/p/10423341.html
Copyright © 2020-2023  润新知