OpenGL原理学习笔记

 说明:简单了解一下OpenGL的工作原理,初步认识计算机对于图形渲染的底层设计与实现,第一次接触,也没学过C艹,欢迎各位批评指正。

一  什么是OpenGL?

    OpenGL是一个开放标准(specification),是一种接口规范,并没有固定实现。每个硬件厂商负责对自己的硬件提供OpenGL接口标准的具体实现。三者关系如下链表:OpenGL API---硬件厂商【各自完成具体实现接口】--使用者【调用OpenGL提供的接口】。

    【厂商的第三方库并不开源,但目前已有开源GL实现的DEMO,如Mesa,有兴趣可自行了解。】

    在日常使用OpenGL时,需要的一些辅助第三方库:GLUT,辅助实现显示,控制流程等功能,因为OpenGL仅仅承担图形渲染的工作,即具体利用图像处理、视图变换、光照以及纹理着色等技术,还原实现了一些虚拟场景:

实例1

实例2

二  OpenGL中不得不提的图形渲染管线(Pipeline

  图形渲染管线(Pipeline)可以看做是一条像素生产流水线,【流水线的输入端是顶点数据和像素数据,经过光栅化后,将片元(Fragment)组合着色成为屏幕可视内容,实现渲染效果】,

  -  固定的图形管线渲染流程如下:

  1 )指定需要完成渲染的几何图元:这些几何图元均是通过顶点指定的,其中包括了点、直线以及三角形等几何要素。

  2) 顶点变换操作:在获得了指定图元后,就可以对定义图元的顶点进行变换处理。

  3 )裁剪、透视触发以及视点适应变换等:将各个顶点进行变换处理后,需要将世界坐标中的图元规范化处理,统一缩放到正规化可视空间CCV中,图元坐标将会从世界坐标转换为窗口坐标;

  2/3这一套处理方式可以从图形渲染管线的主干中分出一个顶点渲染管线分支,该分支将在下一节详细介绍。

  4 )光栅化【1】:坐标变换,几何离散化,即将图元从三维坐标转换为一个二维平面图像。

  5 )片元处理操作:对光栅化后的片元图像进行综合处理:提取纹理、效果、颜色等,对片元进行逐个测试,如像素所有权、剪切、模版测试以及深度测试等,只有当所有测试都通过之后,才会写入帧缓冲区(Frame Buffer)【2】

  6) 片元数据转换为像素数据形式,写入帧缓冲区

图1 OpenGL的图形渲染管线【3】

三  固定管线中的核心——顶点处理管线

  在图像渲染管线中细分出的顶点处理管线主要用于对顶点数据进行降维转换,即将三维空间中的实点转换到二维空间屏幕的坐标系上

  1)数学基础

    在顶点处理管线中,最重要的一个概念在于变换,即上面概念提到的实点的空间转换。但在详细解释顶点处理管线中的空间转换前,我们需要简单了解一下所需的数学基础:齐次坐标 和 矩阵与图形变换

    -  坐标:本质上是一个增加维度的操作,即n维向量(p1,p2,p3,…,pn)增加至第n+1维(p1,p2,p3…,pn,pn+1),方便空间变换中的旋转、平移、透视等操作。

    -  矩阵与坐标变换:图形是由一个个坐标点组成的,通过矩阵与转换矩阵相乘,得到变换后的坐标,即得到了空间变换后的图形。

    举一个简单的例子:

    平移操作:设某几何图形的三维点坐标集合为{ (x,y,z) | x , y , z∈R},先要将图形整体平移(a, b , c),首先,需要将三维点坐标拓展为齐次坐标(x,y,z,1),其次,构造一个4*4的矩阵T:

图2 平移单位矩阵T

    所以,平移操作可以视为:(x,y,z,1)·T = (x+a, y+b, z+c, 1),所以该几何图形经过平移后的三维点坐标集合为{ (x+a, y+b, z+c) | x , y , z∈R}

    

  2)顶点处理管线主要步骤

    2-1)模型视图变换:

① 模型变换主要包括了位移旋转缩放仿射变换【4】,这个部分的模型变换比较简单,上文也提到了关于平移操作的具体矩阵,所以在此就不赘述。模型变换中涉及到的变换大都是仿射变换,仅通过目标几何体的齐次坐标矩阵与操作单位矩阵点乘即可得

到变换位置后的几何体。

上述三个仿射变换操作,在OpenGL中分别对应着:glTranslate*(), glRotate*(), glScale*()。

图3 仿射变换

② 视图变换

主要目的在于将目标几何体从世界坐标中移至摄像机坐标,该变换主要围绕“摄像机”的概念进行定义和实现:

  首先,我们以摄像机作为视点,将视点移动到当前坐标系中的任一固定位置,并以此位置为摄像机坐标系的原点。若要将已处在世界坐标系上的几何体转换到摄像机的坐标体系中,则需要先得到摄像机坐标系与世界坐标系的相对关系,然后在从世界坐标系

中取得几何体,并对该目标几何体做出相应的相对关系处理。

在OpenGL中提供了接口:gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz)

    2-2)光和颜色:

① 光照:

着色需要考虑光照反射光的情况,可以从单点光照模型的情况入手:

光照模型中,我们所能看到的光主要以目标物的反射光为主,先不考虑入射光(有色OR无色)情况,反射光由镜面反射和漫反射组成,除了镜反射光IJ、漫反射光IM外,考虑到外部环境影响,设置环境光为IE,环境反射光=环境光IE*环境反射系数pe。

按照聚光灯模型,反射光IReturn会随着角度和距离的变化而衰减,所以:IReturn=(IJ+IM+IE*pe)*atten(光源到几何体面上某点的距离D)*衰减系数cos(β),再加上全局环境光IE_ALL与自发光e,总体反射光为:

IReturnAll = IReturn + IE_ALL*pe + e

   在OpenGL中,最多可以定义8个光源,每个光源可以设置不同的属性:  

      -  定义光源:Void glLight*(Glenum light, Glenum pname, GLfloat param)

   【light】对应光源

   【pname】参数字段

   【param】参数值

      其中pname可用参数参照下表:


GL_AMBIENT


环境光分量


GL_DIFFUSE


漫反射分量


GL_SPECULAR


镜面反射分量


GL_POSITION


光照位置


GL_SPOT_CUTOFF


聚光灯角度


GL_SPOT_DIRECTION


聚光灯方向向量


GL_SPOT_EXPONENT


比例系数e


GL_CONSTANT_ATTENUATION


聚光灯衰减系数


GL_LINEAR_ATTENUATION


聚光灯衰减系数


GL_QUADRATIC_ATTENUATION


聚光灯衰减系数

     - 激活光源(默认不可用):glEnable(glLight*)

     - 定义目标物的表皮材质:void glMaterialf( GLenum face, Glenum pname, Gfloat param)

    ② 上色:

    OpenGL一般有两种着色模型:平面着色( Flat shading )和平滑着色( Smooth Shading),从效果来看,平滑着色在细节表现上要优于平面着色。而平滑着色又分为Gouraud着色和Phong着色,其中Gouraud着色采用了线性插值的淡化边方法,每个像素的颜色值

    都是通过线性插值的方式得到的,可以平滑的表达色彩和光照的过渡,但缺点在于不善于表达强光区。而Phong则是对法向量进行着色,当前OpenGL不支持该着色模型,即无法进行透视投影变换等后续操作。

    在OpenGL中:

      - 设置OpenGL着色模式的函数:

      void glShadeModel(GL_SMOOTH/GL_FLAT)

      - 提供了如下API接口以供颜色绘制:

      void glColor3f( GLfloat red, GLfloat green, GLfloat blue)

      void glColor4f( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)

      (该着色过程发生在模型视图变换之后)

      - 颜色清除API:

      void glClearColor(GLfloat , GLfloat , GLfloat, GLfloat )  //用于指定空色

      void glClear(GL_COLOR_BUFFER_BIT)    //空色填充,清除画板

    PS:值得一提的是,OpenGL3.0后均采用GLSL语言进行可编程渲染,通过着色器替代顶点处理管线、纹理化和色彩化环节【5】。着色器技术的可编程性可以实现各种图像效果而不受显卡固定管线的限制,提高了图像的画质。

    2-3)投影变换(Porjection):

    在完成了上述的视图模型变换之后,我们已经将几何体从世界坐标中转换到了摄像机坐标系中,接下来,为了在二维平面上表示该几何体,我们需要继续进行下一个步骤——投影变换。投影变换可以简单地理解为,将三维空间的几何体投影到摄像机视锥体的近

    平面和远平面之间。一般投影变换可以分为透视投影、正交投影和斜投影(本文以透视投影为例)。

图4 透视投影和平面投影(近裁面和远裁面之间的空间称之为frustum)【6】

    透视投影遵循近大远小的原理,符合人们日常的视觉心理,具有较好的仿真性。在OpenGL中也提供了两个API接口:

    -   void glFrustum( GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far) 创建一个透视投影矩阵

      【left/right, bottom/top, -near】左下角点( left, bottom, -near)和右上角点( right, top, near)

      【far】远裁面的Z值(负数)

    -  gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar )

      【fovy】x-z平面的视角张角的范围

      【aspect】实际窗口的长宽比x/y

      【zNear】视锥体的近裁面

      【zFar】视锥体的远裁面

    2-4)裁剪、透视除法(clip)

  经过上述处理,如果点位于Frustum的空间中,则投影变换后的几何体点坐标均介于[-1,1]之间,并将x∈[-1,1], y∈[-1,1], z∈[-1,1]的正方体定义为正规化可视空间CCV,裁剪的目的在于裁剪掉CCV外的图元。

透视除法:由于之前为了方便模型视图变换操作,我们用四维齐次坐标作为三维点坐标的代表进行矩阵操作,所以需要通过一定的操作将齐次坐标(x, y, z, q)转换回三维点坐标(x, y, z)。具体操作为:齐次坐标除以第四个分量q,然后丢弃第四个分量,转换回归

   一化的三维坐标(x/q, y/q, z/q)。

    2-5)视口变换(view port)

  此时我们已经得到了归一化坐标,即所有的点坐标都处于CCV中,所以需要通过缩放和位移使其在窗口(屏幕)输出渲染。

  在OpenGL中提供了:

    - void glViewport( Glint x, GLin y, GLsizei width, GLsizei height )

      【x, y】视窗屏幕的左下角坐标

      【width/height】视窗屏幕的实际宽高

    PS:此处需要提醒一下视口变换与投影变换的区别:

图5 视口变换与投影变换的区别【7】

     2-6)最后得到窗口坐标,进行光栅化处理。

 

 【名词解释 & 参考文献】   

【1】光栅化(Rasterize)【像素化或栅格化】的渲染方式:

图元(primitive)指点、线、三角形等基本几何图形,片元(fragment):在光栅化之后,裁剪后称之为片元,片元采用的是屏幕窗口坐标

【2】帧缓冲区:帧缓存OR显存,是屏幕显示画面的直接映像,逻辑上是一组由屏幕上所有像素组成的二维数组,每一个存储单元负责对应屏幕上的一个像素,整个帧缓冲区对应的一帧图像即为当前屏幕显示的画面。一个完整的帧缓冲应当包括颜色缓存、深度缓存、模版缓存、积累缓存以及多重采样缓存

【3】Shreiner Dave. Opengl Programming Guide: The Official Guide To Learning Opengl, Version 2.1, 6/E. Pearson Education India, 2008.

【4】仿射变换:在几何中,一个向量空间进行一次线性变换外加一次平移操作,变换成为另一个向量空间,可以认为线性变换 (向量y=A·向量x )是一次特殊的仿射变换 (向量y=A·向量x+ 向量B )  

【5】【OPENGL】第三篇 着色器基础(一):https://www.cnblogs.com/MyGameAndYOU/p/4691081.html

6】songho:OpenGL Projection Matrix( http://www.songho.ca/opengl/gl_projectionmatrix.html

  【7】图片来自于 :http://www.cnblogs.com/liangliangh/p/4089582.html

  【8】本文的一部分内容是来源这位大神的博客:http://www.twinklingstar.cn/

时间: 2024-10-11 03:22:17

OpenGL原理学习笔记的相关文章

编译原理学习笔记 -- 绪论1

1. 语言处理器 语言处理系统 _________ 经过预 _______ 源程序 --> |预处理器| --> 处理的 --> |编译器| --> 目标汇编程序 -------- 源程序 ------- _______ 可重定位的 ______________ --> |汇编器| --> 机器代码 --> |链接器/加载器| --> 目标机器代码 ------- -------------- ↑ 库文件/可重定位对象文件 预处理器:把源程序聚合在一起,并宏

OpenGL ES学习笔记(二)——平滑着色、自适应宽高及三维图像生成

首先申明下,本文为笔者学习<OpenGL ES应用开发实践指南(Android卷)>的笔记,涉及的代码均出自原书,如有需要,请到原书指定源码地址下载. <Android学习笔记--OpenGL ES的基本用法.绘制流程与着色器编译>中实现了OpenGL ES的Android版HelloWorld,并且阐明了OpenGL ES的绘制流程,以及编译着色器的流程及注意事项.本文将从现实世界中图形显示的角度,说明OpenGL ES如何使得图像在移动设备上显示的更加真实.首先,物体有各种颜色

Unity3D 骨骼动画原理学习笔记

最近研究了一下游戏中模型的骨骼动画的原理,做一个学习笔记,便于大家共同学习探讨. ps:最近改bug改的要死要活,博客写的吭哧吭哧的~ 首先列出学习参考的前人的文章,本文较多的参考了其中的表述: 1.骨骼动画详解 :http://blog.csdn.net/ccx1234/article/details/6641944,不过这篇文章的原文已经被csdn封了:D,可以看看对应的转载的文章也行 2.OpenGL10-骨骼动画原理篇:http://www.cnblogs.com/zhanglitong

编译原理学习笔记(十一)错误处理

错误处理 说明:以老师PPT为标准,借鉴部分教材内容,AlvinZH学习笔记. 1. 目标:编译程序对于语法和语义正确的源程序要正确地编译生成等价的目标代码:而对于错误的源程序不能一发现就停止,而是要能检查出错误的性质和出错位置,并使编译能继续下去,同时尽可能多而准确地发现错误和指出各种错误. 2. 编译器的错误处理能力 诊察各类错误的能力. 报错及时准确(出错位置,错误性质). 一次编译找出错误的多少. 改正错误的能力. 遏制重复错误信息的能力. 3. 错误分类:语法错误.语义错误. 语法错误

lucene原理学习笔记(一)

最近在学习lucene原理方面的知识,将学习中学到的知识和问题记录下来,今天学习的主要内容就是关于索引方面的内容.我们知道lucene是实现全文检索的工具包,要在工程里面加入搜索的功能还需要基于lucene的api进行开发.那么全文检索的步骤分为哪几步呢.全文检索大体上分为两个步骤,索引的创建和搜索索引.于是乎全文检索就涉及到如下几个问题: 1.如何创建索引.2.如果搜索索引.3.索引里面存储的信息都有什么. 索引里面存储的都有什么信息呢,可以用一下的例子来说明,一个文件包含多个字符,当要查询一

TCP/IP协议原理学习笔记

昨天学习了杨宁老师的TCP/IP协议原理第一讲和第二讲,主要介绍了OSI模型,整理如下: OSI是open system innerconnection的简称,即开放式系统互联参考模型,它把网络协议从逻辑上分为了7层.即如上图所示: 1.物理层:主要定义物理设备标准,如网线的接口类型.光纤的接口类型.各种传输介质的传输速率等.它的主要作用是传输比特流(就是由1.0转化为电流强弱来进行传输,到达目的地后在转化为1.0,也就是我们常说的数模转换与模数转换).这一层的数据叫做比特. 2.数据链路层:定

JVM原理学习笔记

最近在阅读 <Inside the JVM> 这本书,结合一些日常工作学习中的感想,随便写一些东西,蜻蜓点水,不必有章法. 关于“单例同步”:     一直有人在问单例对象的并发调用是否需要同步,基本属于“月经帖”了,答案是现成的满天下都是,但真正能让人心里踏实下来的解释寥寥无几.实际上,只要学习了一些JVM的运行原理,解释这个问题就不难了.     如果一个类是单例的,比如某些DAO的设计,那么所有的线程来访问这个类的实例的时候,它们获得的都将是同一个对象,这是不言自明的.如果这些线程的当前

硬件原理学习笔记

1. 硬件是思想的载体,基础为物理学. 人的五感(视觉.听觉.触觉.嗅觉.味觉)接收了大部分的信息: 世界在人的各种感官下形成了对应的映像,然后人类对各种信息作出分析,并对世界做出一定的反馈操作. 这个世界是按一定的原理运行的,而且物质的成份和数量在现实世界中都是预定的. 物质的组成和关系对应软件中的数据结构:物质的状态变化规律对应算法: 2. 为何要了解世界的运作规律和物质构成? 当被刺的时候,本能的反应会痛:当被噪音环绕时,本能会被孤立:总之,人只能在一定的条件下生存,在此条件外就无法适应和

数据挖掘原理学习笔记【1】 绪论

学习绪论,可以让我们从大方向上对一本书有一个总体的把握,从一定的高度俯瞰过后,才能更加清楚每个小部分的意义所在. 即使是绪论,也是有干货的! 1.1 数据挖掘简介 本书中采用如下的数据挖掘定义:数据挖掘就是对观测到的数据集(经常是很庞大的)进行分析,目的是发现未知的关系和以数据拥有者可以理解并对其有价值的新颖方式来总结数据. 上面定义中所说的“观测到的数据”,是与“实验得到的”数据相对而言的,一般来说数据挖掘所处理的数据都是为了其他某个目的已经收集好的,是“顺便的”或者“机会的”样本,而不是为了