背景:

本篇文章主要偏向理论知识的讲解,实践方面后期会进行讲解。opengl的渲染管线中,如果接触3D渲染不多情况下,比如经常做视频滤镜或视频渲染显示的话,经常接触的两个部分就是顶点着色器、片段着色器。如果是做视频渲染的话,这两部分的内容也特别简单,总共也就十几行代码。我们可以从很多地方去摘抄相机流+OpenGL实现渲染的代码,通过把不同地方的滤镜摘抄过来替换掉,就可以实现各种各样的视频滤镜特效了。但当有人问题OpenGL顶点着色器是用来干啥的?OpenGL渲染管线有哪几个步骤?OpenGL每个步骤都分别有什么作用的时候?可能就一脸懵逼的状态。这边文章就是让你更深度的了解OpenGL管线内部如何把你的数据一步一步的渲染到屏幕上的。

顶点着色器:

attribute vec4 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {gl_Position = aPosition;vTextureCoord = aTextureCoord;
}

片段着色器:

precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D sTexture;
void main() {gl_FragColor = texture2D(sTexture, vTextureCoord);
}

OpenGL3.0 渲染管线

OpenGL3.0的渲染管线的总体管线流程图:

上图的渲染管线只是标注了顶点着色器、片段着色器是可编程性的。但并没有对其他的过程进行标注。很难去理解,所以我特意画了下面的渲染流程图,背景用不同的颜色标注。颜色代表了不同阶段的可编程性、可配置型、不可编程不可配置完全GPU控制性,绿色表示该流水线部分完全是可编程性的。黄色表示该流水线部分是可配置性的但不可编程的。蓝色表示该流水线部分是由GPU固定实现的,开发者没有任何的控制权。

可编程性意思就是需要编写Shader,然后让GPU去运行。
可配置型意思是功能OpenGL已经帮我们实现了,OpenGL根据我们的配置决定该渲染管线阶段(如深度测试、模版测试)如何处理。

顶点着色器

顶点着色器是OpenGL渲染管线的第一个阶段,它的数据的输入主要来自CPU,像顶点坐标、顶点颜色、纹理坐标等。OpenGL的顶点着色器每个顶点会执行一次。
顶点着色器的主要作用:坐标变换、计算光照方程、计算顶点颜色等。
下面重点介绍下坐标变换,关于计算光照方程、计算顶点颜色感兴趣的同学可以自己了解。

OpenGL坐标系统

OpenGL的渲染其实是一个把3维的空间转化为2维的屏幕坐标显示的过程。既然是一个3维的空间,首先必须要具备坐标原点、3个坐标轴x/y/z轴。每一个设计师在设计好一个模型之后,这个模型是由一个3维空间中的密密麻麻的点组建而成的。
首先让我们先想象一个场景,足球场里有好多大小不同的足球的场景。如果我们通过OpenGL该如何把该场景渲染到屏幕上?
设计师设计了一个足球场模型,又设计了好多足球模型。足球肯定是在足球场里面的。足球场中有大人玩的大足球,也有小孩玩的小足球,在足球场上该如何体现?那么足球的坐标系统与足球场的坐标系统是什么关系呢?足球在足球场的不同位置又该如何体现呢?我们从不同的视角观看这个操场,场景是否一样?这就设计到OpenGL的坐标系统转换了。

模型空间(局部坐标)

模型坐标是指物体所在的坐标空间,即对象最开始所在的地方。想象你在一个建模软件(比如说Blender)中创建了一个立方体。你创建的立方体的原点有可能位于(0, 0, 0),即便它有可能最后在程序中处于完全不同的位置。甚至有可能你创建的所有模型都以(0, 0, 0)为初始位置。所以,你的模型的所有顶点都是在模型坐标空间中:它们相对于你的物体来说都是局部的。

世界空间

如果我们将我们所有的物体模型导入到程序当中,它们有可能会全挤在世界的原点(0, 0, 0)上,这并不是我们想要的结果。我们想为每一个物体定义一个位置,从而能在更大的世界当中放置它们。世界空间中的坐标正如其名:是指顶点相对于(游戏)世界的坐标。如果你希望将物体分散在世界上摆放(特别是非常真实的那样),这就是你希望物体变换到的空间。物体的坐标将会从局部变换到世界空间;该变换是由模型矩阵(Model Matrix)实现的。
模型矩阵是一种变换矩阵,它能通过对物体进行位移、缩放、旋转来将它置于它本应该在的位置或朝向。你可以将它想像为变换一个房子,你需要先将它缩小(它在局部空间中太大了),并将其位移至郊区的一个小镇,然后在y轴上往左旋转一点以搭配附近的房子。你也可以把上一节将箱子到处摆放在场景中用的那个矩阵大致看作一个模型矩阵;我们将箱子的局部坐标变换到场景/世界中的不同位置。

观察空间

观察空间经常被人们称之OpenGL的摄像机(Camera)(所以有时也称为摄像机空间(Camera Space)或视觉空间(Eye Space))。观察空间是将世界空间坐标转化为用户视野前方的坐标而产生的结果。因此观察空间就是从摄像机的视角所观察到的空间。而这通常是由一系列的位移和旋转的组合来完成,平移/旋转场景从而使得特定的对象被变换到摄像机的前方。这些组合在一起的变换通常存储在一个观察矩阵(View Matrix)里,它被用来将世界坐标变换到观察空间。在下一节中我们将深入讨论如何创建一个这样的观察矩阵来模拟一个摄像机。

裁剪空间

在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。
将观察坐标变换为裁剪坐标的投影矩阵可以为两种不同的形式,每种形式都定义了不同的平截头体。我们可以选择创建一个正交投影矩阵(Orthographic Projection Matrix)或一个透视投影矩阵(Perspective Projection Matrix)。
正交投影矩阵、透视投影矩阵感兴趣的可以查资料了解,这里由于篇幅的原因不再讲解。

屏幕空间

屏幕空间是一个二维空间,因此,必须把顶点从裁剪空间投影到屏幕空间中,来生成对应的2d坐标。
下面分别用一张图和Shader描述下空间变换:

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
attribute vec4 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {gl_Position = projection * view * model * aPosition;vTextureCoord = aTextureCoord;
}

裁剪

由于我们的场景很大,不可能把所有的场景都显示出来,所以必须进行裁剪。裁剪过程是不可编程的,但是可以根据我们之前配置的投影矩阵控制裁剪场景的大小。

屏幕映射

屏幕映射的过程就是上文介绍的OpenGL坐标系统中由裁剪空间到屏幕空间的过程。屏幕映射过程完全由OpenGL控制。

图元装配

OpenGL中的图元主要包括点、直线、三角形。图元装配就是根据我们指令确定这些简单图元由哪些顶点组成。图元装配阶段完全由OpenGL控制。

光栅化

光栅化主要包括3个阶段:

  1. 计算每个图元覆盖率哪些像素
  2. 通过顶点差值计算像素的颜色
  3. 输出每个图元的片元序列

需要主要的是一个片元并不是真正意义上的像素。而是包含了很多状态的集合,这些状态用于计算像素的最终颜色,这些状态包括了(但不限于)它的屏幕坐标、深度信息、法线、纹理坐标等。

片元着色器

片元着色器是OpenGL渲染管线非常重要的可编程着色阶段,每一个片元都会经过片元着色器的处理。虽然我们可以通过编程的手段完成很多绚丽的效果,但它的局限性在于它仅影响单个片元。你不能在片元着色器中获取它临近片元的信息。正式它的独立性,才保证了OpenGL高并发的工作。该阶段只是决定该像素的颜色值,但并不能决定渲染到屏幕的颜色值,后面还需要逐片元操作。

逐片元操作

逐片元操作阶段都是可以配置的。逐片元过程大致如下:

裁剪测试

剪裁测试用于限制绘制区域。我们可以指定一个矩形的剪裁窗口,当启用剪裁测试后,只有在这个窗口之内的像素才能被绘制,其它像素则会被丢弃。换句话说,无论怎么绘制,剪裁窗口以外的像素将不会被修改。
可以通过下面的代码来启用或禁用剪裁测试:

glEnable(GL_SCISSOR_TEST);   // 启用剪裁测试
glDisable(GL_SCISSOR_TEST); // 禁用剪裁测试

可以通过下面的代码来指定一个位置在(x, y),宽度为width,高度为height的剪裁窗口。

glScissor(x, y, width, height);

模版测试

模板测试需要一个模板缓冲区。
模板缓冲区(Stencil Buffer):与颜色缓冲区和深度缓冲区类似,模板缓冲区可以为屏幕上的每个像素点保存一个无符号整数值。这个值的具体意义视程序的具体应用而定。在渲染的过程中,可以用这个值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新相应的像素点的颜色值。这个比较的过程被称为模板测试。模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。如果模板测试通过,则相应的像素点更新,否则不更新。就像使用纸板和喷漆一样精确的混图一样,当启动模板测试时,通过模板测试的片段像素点会被替换到颜色缓冲区中,从而显示出来,未通过的则不会保存到颜色缓冲区中,从而达到了过滤的功能。

通过glEnable/glDisable可以启用或禁用模板测试。

glEnable(GL_STENCIL_TEST);   // 启用模板测试
glDisable(GL_STENCIL_TEST); // 禁用模板测试

深度测试

深度缓冲区:存储每个像素的深度值,当启动深度测试时,片段像素深度值和深度缓冲区深度值进行比较,决定片段哪些像素点数据可以替换到颜色缓冲区中。

深度测试需要深度缓冲区,跟模板测试需要模板缓冲区是类似的。如果使用GLUT工具包,可以在调用glutInitDisplayMode函数时在参数中加上GLUT_DEPTH,这样来明确指定要求使用深度缓冲区。
深度测试和模板测试的实现原理很类似,都是在一个缓冲区保存像素的某个值,当需要进行测试时,将保存的值与另一个值进行比较,以确定是否通过测试。两者的区别在于:模板测试是设定一个值,在测试时用这个设定值与像素的“模板值”进行比较,而深度测试是根据顶点的空间坐标计算出深度,用这个深度与像素的“深度值”进行比较。也就是说,模板测试需要指定一个值作为比较参考,而深度测试中,这个比较用的参考值是OpenGL根据空间坐标自动计算的。

通过glEnable/glDisable函数可以启用或禁用深度测试。

glEnable(GL_DEPTH_TEST);   // 启用深度测试
glDisable(GL_DEPTH_TEST); // 禁用深度测试

至于通过测试的条件,同样有八种,与Alpha测试中的条件设置相同。条件设置是通过glDepthFunc函数完成的,默认值是GL_LESS。
glDepthFunc(GL_LESS);

与模板测试相比,深度测试的应用要频繁得多。几乎所有的三维场景绘制都使用了深度测试。正因为这样,几乎所有的OpenGL实现都对深度测试提供了硬件支持,所以虽然两者的实现原理类似,但深度测试很可能会比模板测试快得多。当然了,两种测试在应用上很少有交集,一般不会出现使用一种测试去代替另一种测试的情况。

混合

为什么需要混合?我们要知道,这里所讨论的渲染过程是一个物体接着一个物体渲染到屏幕上面的。每个像素的颜色信息被存储在一个名为颜色缓冲区的地方。因此当我们执行渲染的时候,颜色缓冲区往往已经有了上次渲染的数据。那么我们这次渲染是使用完全覆盖掉,还是进行混合处理显示半透明的效果。只就是混合所要解决的问题。

当模型经过上面层层的测试及混合后就会显示到我们的屏幕上了。如果是离屏渲染的化就看不到效果了。

OpenGL渲染管线解析相关推荐

  1. 小强学渲染之OpenGL渲染管线详析

    什么是OpenGL? OpenGL是一套图形硬件的软件API接口库,它直接和GPU交互,将3D场景渲染绘制到2D屏幕上.总结说,OpenGL的功能是将程序中定义的各种2D或3D模型绘制到帧缓存中,或者 ...

  2. OpenGL 渲染管线理论

    这几天稍微看了一些关于GLSL的顶点着色以及片元着色的一些相关知识.目前来讲还有一个着色器则是Geometry_shader..我的显卡用不了这个功能..当然有点遗憾>_<..       ...

  3. 《OpenGL编程指南(原书第9版)》——1.4 OpenGL渲染管线

    1.4 OpenGL渲染管线 OpenGL实现了我们通常所说的渲染管线(rendering pipeline),它是一系列数据处理过程,并且将应用程序的数据转换到最终渲染的图像.图1-2所示为Open ...

  4. OpenGL: 渲染管线理论

    学习着色器,并理解着色器的工作机制,就要对OpenGL的固定功能管线有深入的了解. 零.首先要知道几个OpenGL的术语 渲染(rendering):计算机根据模型(model)创建图像的过程. 模型 ...

  5. OpenGL 渲染管线理论

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 学习着色 ...

  6. OpenGL渲染管线之简单示例(五)

    前言:这一章我们将对前面的所有知识进行实践,通过OpenGL编程,完成一个简单的OpenGL程序.你可以通过访问我的GitHub获取我学习的HelloOpenGL项目.这个项目需要的所有头文件及库均配 ...

  7. opengl渲染管线(Graphics Pipeline)

    opengl渲染管线 前言:在OpenGL中,任何事物都在3D空间中,但是屏幕和窗口都是2D像素数组,因此OpenGL大部分工作都是将3D坐标转化为适应屏幕的2D像素.3D坐标转化为2D坐标的过程是O ...

  8. OpenGL渲染管线介绍

    一.概述 OpenGL是跨平台计算机图形应用程序的应用规范,广泛应用于仿真.游戏.GIS系统等领域,实现二三维图形的渲染.OpenGL渲染过程需要经历CPU.GPU两个阶段,CPU中进行图形计算,完成 ...

  9. 红宝书阅读笔记——OPENGL渲染管线

    之前读的时候一直觉得红宝书是很艰涩难懂的,不如NEHE的教程简单. 后来才发觉是自己没基础,几番折腾之后也只能用OPENGL做些简单的东西.半年没写,连glBegin都给忘了. 图形学的大作业要求写个 ...

最新文章

  1. 新建本地仓库,同步远程仓场景,出现git branch --set-upstream-to=origin/master master 解决方法...
  2. python基础学习-5(包与模块)
  3. 华为鲲鹏高校行长沙启航,助力基础研究成果转化
  4. IC/FPGA笔试题分析(五)
  5. 通过jstack定位在线运行java系统故障_案例1
  6. 数据中心机房的监控系统是否重要?
  7. Qt Creator管理C ++后端对象
  8. ExtJS中如何根据combobox的选值,动态地决定组件的显隐?
  9. 编写一个程序实现方法的覆盖java_编写Java程序代码必须先声明一个____,然后在其中编写实现需求的业务代码。...
  10. 使用Dockerfile制作JDK+tomcat镜像
  11. linux-进程的理解-进程的状态与生命周期
  12. python制作安装包_如何制作python安装模块(setup.py)
  13. VS2010与.NET4系列 10. VS2010代码智能感知增强
  14. 并发编程: 生产消费模型、死锁与Rlock、线程、守护线程、信号量、锁
  15. JavaScript高级教程(javascript实战进阶)
  16. 互联网公益陷入信任危机,智慧公益能否力挽狂澜?
  17. 【day02】选择题题解
  18. 5 种 无线协议的特点:lora、NB-IOT、ZigBee、WiFi、BLE
  19. TyoeScript
  20. pyramid框架_Python Pyramid Web框架简介

热门文章

  1. node-logger
  2. python scrapy请求手机版QQ空间数据
  3. MapBar的Api使用简略说明(上)
  4. 深度解读2023年巴菲特致股东的信
  5. java程序创建桌面图标_Java桌面应用程序创建系统托盘图标
  6. 解决Windows远程桌面连接每次都提示输入密码的问题,远程桌面记不住密码
  7. shell 记录日志
  8. iPhone图片格式转换之heic转jpg
  9. 老家见闻--一个程序员的成长史(8)
  10. 02月刊(上) | 微信小程序