在C# 使用SharpGL-Hello Word代码详解中的Resized函数里,出现了Perspective和LookAt,将Hello Word代码详解中的此部分复制过来,继续讲解里面的内容

        private void openGLControl_Resized(object sender, EventArgs e){//  TODO: Set the projection matrix here.//  Get the OpenGL object.OpenGL gl = openGLControl.OpenGL;//  Set the projection matrix.gl.MatrixMode(OpenGL.GL_PROJECTION);//设置OpenGL矩阵模式,OpenGL都是通过矩阵操作的,不同的矩阵模式对应不同的操作//OpenGL.GL_PROJECTION:投影矩阵//  Load the identity.gl.LoadIdentity();//  Create a perspective transformation.gl.Perspective(60.0f, (double)Width / (double)Height, 0.01, 100.0);//透视投影设置//简单点理解就是,设置相机镜头:广角大小、视图长宽比、视野近点、视野远点//投影的目的是定义一个视景体,使得视景体外多余的部分不会显示//投影包括透视投影和正式投影,后续详讲//  Use the 'look at' helper function to position and aim the camera.gl.LookAt(-5, 5, -5, 0, 0, 0, 0, 1, 0);//设置相机参数,三个参数一组,分别代表:相机位置、镜头正对位置、相机正向位置//上述表示:相机放在(-5,5,-5)位置,镜头对着(0,0,0)点,相机正向与Y轴一致//  Set the modelview matrix.gl.MatrixMode(OpenGL.GL_MODELVIEW);//设置OpenGL矩阵模式,OpenGL.GL_MODELVIEW:模型视图矩阵}

一、**public void MatrixMode(uint mode)**函数
此函数主要是用来设定当前OpenGL操作的矩阵堆栈目标,由于OpenGL主要是一个大很大的状态机,运算都采用矩阵预算,通过MatrixMode可以设置当前操作的矩阵目标。一般,在需要绘制出对象或要对所绘制对象进行几何变换时,需要将变换矩阵设置成模型视图模式;而当需要对绘制的对象设置某种投影方式时,则需要将变换矩阵设置成投影模式;只有在进行纹理映射时,才需要将变换矩阵设置成纹理模式。
mode参数说明:
1、GL_MODELVIEW:指定矩阵堆栈目标是模型视图矩阵,可以在执行此命令后,输出自己的物体图形了,以及执行缩放、平移、旋转等几何变换。
2、GL_PROJECTION:指定矩阵堆栈目标是投影矩阵,执行此命令后,可以设置投影效果参数,以及相机参数。简单点理解就是,设置绘制出来的图像呈现到屏幕的效果:视图、视角、成像规则等。
3、GL_TEXTURE:指定矩阵堆栈目标是投影矩阵,执行此命令后,可以对纹理贴图进行操作。

二、几何变换
OpenGL变换实际上是通过矩阵运算来实现。无论是平移、旋转还是缩放,都是通过在当前矩阵的基础上乘以一个新的矩阵来达到目的。矩阵运算是一个比较基础的运算,在此就不做说明,需要补课的同学可以自己上网搜索。
一般几何变换操作需要以下几个步骤:
1、在做几何变换之前,需要将OpenGL当前矩阵堆栈设置为视图矩阵,需要用到matrixMode函数:

            //  Set the modelview matrix.gl.MatrixMode(OpenGL.GL_MODELVIEW);//设置OpenGL矩阵模式,OpenGL.GL_MODELVIEW:模型视图矩阵

2、在做几何变换前,将OpenGL当前矩阵设置为单位矩阵,确保后面的几何矩阵变换结果可寻,需要用到LoadIdentity函数:

            //  Load the identity.gl.LoadIdentity();//设置当前矩阵为单位矩阵

3、此时就可以做几何变换操作了,几何变换操作主要涉及三个操作:平移、旋转、缩放。
**平移函数:Translate(xPos, yPos, zPos):**把当前矩阵跟平移矩阵相乘,可以将当前矩阵矢量移动(xPos,yPos,zPos)量。其中,xPos:X轴方向平移量,yPos:Y轴方向平移量,zPos:Z轴方向平移量。
**旋转函数1:Rotate(anglex,angley,anglez):**以欧拉角的方式对当前矩阵进行旋转,三个参数分别对应:俯仰角(Pitch)、偏航角(Yaw)和滚转角(Roll)

此图出自LearnOpenGL CN网站
**旋转函数2:Rotate(angle,x,y,z):**以旋转角度+旋转轴方式对当前矩阵进行旋转,其中,angle:旋转角度,(x,y,z):以向量(x,y,z)为旋转轴,angle方向遵循右手螺旋法则。
**缩放函数:Scale(scalex,scaley,scalez):**其中三个参数分别对应X轴方向缩放比例,Y轴方向缩放比例,Z轴方向缩放比例。

三、投影变换
投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上,可通过投影变换,改变绘制图形投影到屏幕上的视图、视角等效果。简单点理解就是,相机拍照时所采用的镜头广角、滤镜深度、视野长宽比、相机位置、相机角度、相机正方向等,进而拍摄/呈现出想要的照片效果。
若需要投影操作,需要将OpenGL当前矩阵设置为投影矩阵:

            //  Set the projection matrix.//将当前矩阵设置成参数所指定的模式,以满足不同绘图所需执行的矩阵变换gl.MatrixMode(OpenGL.GL_PROJECTION);//GL_PROJECTION,对投影矩阵堆栈应用随后的矩阵操作。可以在执行此命令后,为我们的场景增加透视。

OpenGL最常用的两种投影变换有:透视投影和正交投影。
1、透视投影:
其实就是一个视椎体,它符合人的观察经验,即离视点近的物体大,离视点远的物体小,远到极点就消失,成为灭点。

透视投影:Perspective(double fovy, double aspect, double zNear, double zFar),其中:
fovy:是控制视野在XY平面的角度,范围是0~180°,对应相机镜头的广角。
aspect:是视野窗口的纵横比,对应相机视野长宽比。
zNear、zFar:拍摄物体离相机的近点和远点,只有在这个范围内的物体才会拍摄呈现出来,超出这个范围的物体都被裁切掉。注意,这两个值都是相对于相机点位为基零点进行计算的。
2、正交投影
正交投影又叫平行投影,这种投影是一个矩形长方体的平行管道。它最大的特点是,无论物体距离相机多远投影后的物体大小尺寸不变。

正交投影:Ortho(double left, double right, double bottom, double top, double zNear, double zFar),这些参数都比较简单和直观,参考上图就可以了。
做一个简单的程序,对比看看透视投影和正交投影的效果,绘制一个椎体,从椎体上方往下看,同样的观测点,呈现出的椎体会有不同的视觉效果。
先写两个投影矩阵函数,设定同一个观测点(LookAt):

        private void Perspective_Sample(SharpGL.OpenGL gl){gl.MatrixMode(OpenGL.GL_PROJECTION);gl.LoadIdentity();gl.Perspective(60.0, (double)(this.Width / this.Height), 0.01, 100.0);gl.LookAt(0.0f, 0.0f, 5, 0, 0, 0, 0, 1, 0);//相机参数gl.MatrixMode(OpenGL.GL_MODELVIEW);}private void Ortho_Sample(SharpGL.OpenGL gl){gl.MatrixMode(OpenGL.GL_PROJECTION);gl.LoadIdentity();gl.Ortho(-2, 2, -2, 2, 0.01, 100.0);gl.LookAt(0.0f, 0.0f, 5, 0, 0, 0, 0, 1, 0);//相机参数gl.MatrixMode(OpenGL.GL_MODELVIEW);}
  绘制一个简单的椎体:
        private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs args){SharpGL.OpenGL gl = openGLControl1.OpenGL;gl.ClearColor(0, 0, 0, 0);gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);if (Projective_Mode == 0)//选择当前投影是透视投影还是正交投影Perspective_Sample(gl);else if (Projective_Mode == 1)Ortho_Sample(gl);gl.Begin(OpenGL.GL_LINE_STRIP);gl.LoadIdentity();gl.Vertex(0, 0, 0);gl.Vertex(1, 0, 0);gl.Vertex(1, 1, 0);gl.Vertex(0, 1, 0);gl.Vertex(0, 0, 0);gl.Vertex(0.5, 0.5, 1);gl.Vertex(1, 0, 0);gl.Vertex(0.5, 0.5, 1);gl.Vertex(1, 1, 0);gl.Vertex(0.5, 0.5, 1);gl.Vertex(0, 1, 0);gl.End();gl.Flush();}



四、LookAt
LookAt(double eyex, double eyey, double eyez, double centerx, double centery, double centerz, double upx, double upy, double upz)
视点变换函数,其实就是在设置相机参数:相机位置、相机朝向、相机正方向等参数。如果没有调用glLookAt设置视图矩阵,默认情况下,相机会被设置为位置在世界坐标系原点,指向z轴负方向,朝上向量为(0,1,0)。
(eyex,eyey,eyez):定义相机在世界坐标系中的位置坐标。
(centerx,centery,centerz):定义相机正对着的世界坐标系中的点的位置坐标,成像后这一点会位于画板的中心位置。
(upx,upy,upz):定义相机本身的朝向。
以观察者的角度去看这几个参数就很容易理解了。第一组参数是定义人站在距离物体有多远处,第二组参数是定义人眼看向世界坐标系中的哪个方向,有时候屏幕上黑黑的什么也看不到,可能就是这组参数设置的方向不对,有可能物体就在你身后不远处,第三组参数是人的朝向,也表示一个方向,这个朝向跟视线是垂直的。
还以上面的椎体为例,从不同角度观测椎体呈现效果。
相机点(0,0,5),观测点(0,0,0),相机朝向(0,1,0),呈现效果:

相机点(0,-5,5),观测点(0,0,0),相机朝向(0,0,1),呈现效果:

补偿说明一下(upx,upy,upz)相机方向三个参数:
同样的相机位置,同样的观测位置,对同一个小美女(网上搜的)拍背影照片,相机方向分别是(0,0,1)Z轴正方向和(1,0,0)X轴正方向,拍摄出来的照片对比如下:

可以写一个简单的按键操作,来修改相机点坐标,通过按键控制相机参数,呈现出视图变换的效果:

        private void Key_Down(object sender, KeyEventArgs e){if (e.KeyCode == Keys.Q)Projective_Mode = 0;else if (e.KeyCode == Keys.W)Projective_Mode = 1;if (e.KeyCode == Keys.I)LookAt_eye_x = LookAt_eye_x + 0.1f;else if (e.KeyCode == Keys.J)LookAt_eye_x = LookAt_eye_x - 0.1f;else if (e.KeyCode == Keys.O)LookAt_eye_y = LookAt_eye_y + 0.1f;else if (e.KeyCode == Keys.K)LookAt_eye_y = LookAt_eye_y - 0.1f;else if (e.KeyCode == Keys.F)LookAt_center_x = LookAt_center_x + 0.1;else if (e.KeyCode == Keys.C)LookAt_center_x = LookAt_center_x - 0.1;else if (e.KeyCode == Keys.G)LookAt_center_y = LookAt_center_y + 0.1;else if (e.KeyCode == Keys.V)LookAt_center_y = LookAt_center_y - 0.1;}

将投影矩阵函数做适当修改:

        double LookAt_eye_x = 0.0f;double LookAt_eye_y = -5f;double LookAt_eye_z = 0f;private void Perspective_Sample(SharpGL.OpenGL gl){gl.MatrixMode(OpenGL.GL_PROJECTION);gl.LoadIdentity();gl.Perspective(60.0, (double)(this.Width / this.Height), 0.01, 100.0);gl.LookAt(LookAt_eye_x, LookAt_eye_y, 5, LookAt_center_x, LookAt_center_y, 0, 0, 0, 1);gl.MatrixMode(OpenGL.GL_MODELVIEW);}private void Ortho_Sample(SharpGL.OpenGL gl){gl.MatrixMode(OpenGL.GL_PROJECTION);gl.LoadIdentity();gl.Ortho(-2, 2, -2, 2, 0.01, 100.0);gl.LookAt(LookAt_eye_x, LookAt_eye_y, 5, LookAt_center_x, LookAt_center_y, 0, 0, 1, 0);gl.MatrixMode(OpenGL.GL_MODELVIEW);}

以上讲解的不是很深入,只是对函数的直观应用做了说明,对一些需要深入了解其中变换和投影的一些基本矩阵运算原理的同学,可以参考以下连接,当然也非常感谢各位大神整理的资料:
1、LearnOpenGL CN
2、投影矩阵和视口变换矩阵
3、sharpgl GitHub主页

C# 使用SharpGL-Perspective和LookAt相关推荐

  1. WebGl 球面计算公式

    概要 以下所涉及到的数学模型包括: WebGl 的球体模型构建 WebGl 场景交互时视角变换的方法 WebGl 中 3D 空间的点在二维平面上的投影 360 度播放器的视频流的处理 以上是全景播放器 ...

  2. SharpGL学习笔记(一) 平台构建与Opengl的hello World

    (一)平台构建与Opengl的hello World OpenGL就是3d绘图的API,微软针和它竞争推出D3D,也就是玩游戏时最常见的DirectorX组件中的3d功能. 所以不要指望windows ...

  3. SharpGL学习笔记(一) 平台构建与Opengl的hello World (转)

    (一)平台构建与Opengl的hello World OpenGL就是3d绘图的API,微软针和它竞争推出D3D,也就是玩游戏时最常见的DirectorX组件中的3d功能. 所以不要指望windows ...

  4. OpenGL视角LooAt及Perspective理解

    在: http://blog.csdn.net/yulinxx/article/details/59538755 的基础上,修改 main.cpp 理解 glm::perspective 和 glm: ...

  5. OpenGL相机自由移动旋转缩放,四元数,欧拉角,LookAt

    OpenGL相机自由移动旋转缩放,四元数,欧拉角,LookAt 定义相机 摄像机位置 右轴 上轴 Look At 自由移动相机 左右移动 移动速度 视角移动 欧拉角 通过欧拉角计算实际的方向向量 缩放 ...

  6. Transform-style和Perspective属性

    在<CSS3 Transform--transform-origin>一文中主要介绍了CSS3 Transform属性中的transform-origin属性的使用,其实在transfor ...

  7. RCP中Perspective中,设置各个view的大小比例

    为什么80%的码农都做不了架构师?>>>    其实一般情况下,在Perspective 中添加View的时候,是新建一个Folder,然后再把View添加到Folder当中的.   ...

  8. Feature Selection: A Data Perspective --阅读笔记1 特征选择的概述

    摘要 INTRODUCTION Traditional Categorization of Feature Selection Algorithms Feature Selection Algorit ...

  9. Computer Systems A Programmer’s Perspective ----阅读翻译日志

    2019独角兽企业重金招聘Python工程师标准>>> 借助google 翻译读一下这本书吧,做个记录 Computer Systems A Programmer's Perspec ...

最新文章

  1. 勒索软件出新招,小心你的隐私和財产安全!
  2. 从零开始数据科学与机器学习算法-线性回归-02
  3. pptv手机端html,影视资源持续更新,PPTV手机化身看片神器
  4. python如何输出两列数据_如何用python将一列数据分为两列?
  5. 数据库中char, varchar, nvarchar的差异
  6. Springboot项目结构浅析
  7. 环境变量environ
  8. 练习1.account表 添加一条记录
  9. Android View体系(五)从源码解析View的事件分发机制
  10. python字典默认排序_Python字典练习:设置默认获取排序,小,知识点,setdefaultgetsorted...
  11. java中 获取classpath路径
  12. 『Python动手学』PyQt5入门教程
  13. SwiftyJson 的初步理解
  14. html登录页面修改背景图片,html网页背景图片设置
  15. gopro lrv文件和thm文件
  16. 实习期间的一些思考整理(4)2018.4.14~4.16
  17. 写latex 遇到bib中参考文献 的俄文人名(类似于带有声调的拼音字母)如何转义?
  18. Vue3.2 使用 汉字转拼音的插件pinyin-pro 库
  19. 为什么说品牌推广离不开软文营销呢?一文告诉你软文营销的优势
  20. dos系统不能安装python模块_dos窗口运行python文件提示找不到模块

热门文章

  1. 元宇宙之XR(02)VR概念解读 分类说明
  2. 正弦稳态电路的阻抗和功率
  3. 内部排序 (四):选择排序 Selection Sorting (简单选择排序、堆排序)
  4. FH Admin fhadmn 源码项目下载获取 Java后台 springmvc mybatis SSM
  5. 完美解决Mac无法写入NTFS硬盘——Mounty for NTFS
  6. [nrf51][nrf52] nrfconnect 安装说明指南
  7. 通过HbuilderX启动 微信开发者工具
  8. gjt常用命令---chalee
  9. MAC常用命令及快捷键
  10. 【python】详解multiprocessing多进程-Pool进程池模块(二)