1. GLSL (Graphics Library Shader Language),什么是GLSL?

GLSL是在OpenGL2.0时开始引入的一种语言,它可以让开发者定制自己的着色方式,而不是像原来一样走固定渲染管线。我们知道如果要达到一些色彩的渲染效果,需要一大堆以gl开头的函数,如glLightfv()、glMaterialfv()、glFogv()等等,而使用GLSL,则可以很简单地使用OpenGL的着色语言来达到上述函数的效果,有时候使用上述函数无法达到的效果,GLSL都可以做到。使用GLSL还有一个好处就是如果需要在运行时改变渲染效果,那么使用GLSL是非常方便的,而OpenGL2.0以前的那些函数可能因为需要调换次序等原因无法做到这样的效果。综上所述,GLSL对于开发现代应用程序还是非常有用的。

OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编程的语言,也即开发人员写的短小的自定义程序,他们是在图形卡的GPU (Graphic Processor Unit图形处理单元)上执行的,代替了固定的渲染管线的一部分,使渲染管线中不同层次具有可编程性。比如:视图转换、投影转换等。GLSL(GL Shading Language)的着色器代码分成2个部分:Vertex Shader(顶点着色器)和Fragment(片断着色器),有时还会有Geometry Shader(几何着色器)。负责运行顶点着色的是顶点着色器。它可以得到当前OpenGL 中的状态,GLSL内置变量进行传递。GLSL其使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。

GLSL简单实例分析

#ifdef GL_FRAGMENT_PRECISION_HIGH
  precision highp float;
  #else
  precision mediump float;
  #endif
   //上面是预编译,如果设备支持就使用高精度模式(更高精度的浮点运算),否则使用低精度模式  uniform vec2 resolution;
   //只读的全局变量,是一个二维浮点向量,表示当前设备的分辨率  void main(void)
   //用于着色的主函数
  {
      vec2 uv = gl_FragCoord.xy / resolutionCoord.xy
       //当前着色像素坐标与设备分辨率的比值
      vec4 wave_color = vec4(uv, 1.0, 1.0);
       //uv设置了当前像素的红绿(RG)程度,蓝色(B)程度固定为1.0,透明度(A)固定为1.0
      gl_FragColor = wave_color;
       //将颜色(一个四维向量)赋值给gl_FragColor,这是设置当前像素颜色的固定写法
  }


我们可以看到GLSL语言风格与C语言非常相似,上手比较容易。
二维浮点向量vec2 vec相当于C语言中的数组float vec[2]。
事实上GLSL也支持数组,如vec2 vec[2]相当于C语言中的二维数组float vec[2][2]

2.什么是Shader?
着色器(Shader)是用来实现图像渲染的,用来替代固定渲染管线的可编辑程序。其中Vertex Shader主要负责顶点的几何关系等的运算,Pixel Shader主要负责片源颜色等的计算。

着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编辑性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。

顶点着色器Vertex Shader 和片段(片元)着色器 Fragment Shader

opengl es着色器区别_顶点着色器

一)、顶点着色器的定义:

        Vertex Shader顶点着色器,实现了一种通用的可编程方法操作顶点。

在编程中,顶点着色器的输入主要有:

1.Attributes——属性,顶点矩阵支持的Per_vertex数据

2.Uniforms——顶点着色器使用的常量数据

3.Samplers——被Uniforms使用的特殊类型,在顶点着色器的贴图中使用(是可选的)

4.ShaderProgram——顶点着色器编程源码或可执行的部分

 

对应的,顶点着色器的输出叫做varying变量:

在最初的光栅化阶段,这些变量被计算,作为片段着色器的输入,从顶点着色器的矩阵使用插补的方法产生片段着色器的变量,输入和输出如下图所示:

opengl es着色器区别_opengl es着色器区别_02

二)、顶点着色器的作用:

        顶点着色器被使用在传统的基于顶点的操作,例如位移矩阵、计算光照方程、产生贴图坐标。顶点着色器被应用指定,应用于客户的顶点转化。

        假设我们此时要编写一个顶点着色器,需要有一个位置和颜色数据这两个输入属性,其中输入位置数据时4X4的矩阵,输出是变换后的位置和颜色:

opengl es着色器区别_opengl es着色器区别_03

上述程序中,首先定义了一个uniform变量u_mvpMatrix,此变量用于存储模型的关联视图和投射矩阵(也就是输入和输出的位置转换关系),然后声明了a_position和a_color这两个表示顶点着色器的两个输入属性(位置和颜色),而gl_Position和v_color则表示输出的两个属性,其中gl_Position无需声明,因为它是OpenGL的内部属性。

三)、基元装配和光栅化:

        顶点着色器的下一个阶段是图元装配。基本的图元(primitive)为点、线、三角形等。将顶点数据计算成一个个图元,在这阶段会执行裁剪,透视分割,视口变换操作后进入光栅化阶段。

        基元(图元):是能被OpenGL ES绘制的几何物体,这些绘图命令描述了一个顶点属性和基元几何体以及基元类型的集合。图元是由顶点组成的,顶点属性包括计算位置、颜色和贴图坐标的信息,他们将被输入到片段着色器中。

        顶点着色器能绘制的几何图元包括三角形、直线、点,对每个图元必须判断是否位于投影平截体内,如果图元不完全在平截体内部,将被视图平截体剪贴,如果完全在平截体外,将被丢弃,然后顶点位置被转变为屏幕坐标,剔除操作也能够舍弃一些图元,依据图元位于正面还是背面,剪切和剔除后,图元进入光栅化阶段。

        光栅化:是转化图元为二维片段的过程,被片段着色器执行,二维的片段像素能够被绘制在屏幕上。

opengl es着色器区别_GLSL_04

 

原文链接:

片元着色器

片元着色器程序是用来描述片段上执行操作(如颜色混合)的片元着色器程序源代码/可执行文件。
在片元着色器中的输入有:

  • 在光栅化阶段通过插值为每个片段生成的纹理坐标。
  • uniform 修饰的属性, 可以传递在片元着色器需要使用的数据等。
  • sampler2D 修饰的属性, 传递纹理对象,实际上传递的是对应的纹理单元(texture unit)索引号。

片元着色器的常用输出:

  • gl_FragColor 输出每个片段的颜色。

在片元着色器的业务处理有:

  • 计算颜色
  • 获取纹素
  • 往像素点中填充颜色值
    它可以用于图片/视频中每个像素的颜色填充【比如给视频添加滤镜,实际上就是将视频中每个图片的像素点颜色填充进行修改】

opengl es着色器区别_顶点着色器_05

像素归属测试: 确定帧缓存区中位置(Xw,Yw)的像素目前是不是归属于OpenGL ES所有. 例如,如果⼀个显示OpenGL ES帧缓存区View被另外⼀个View所遮蔽.则窗口系统可以确定被遮蔽的像素不属于OpenGL ES上下⽂。从而不全显示这些像素。而像素归属测试是OpenGL ES的一部分,它不由开发者开人为控制,而是由OpenGL ES内部进行.
裁剪测试: 裁剪测试确定(Xw,Yw)是否位于作为OpenGL ES状态的一部分裁剪矩形范围 内。如果该⽚段位于裁剪区域之外,则被抛弃。
深度测试: 输⼊片段的深度值进步比较,确定片段是否拒绝测试
混合: 混合将新生成的⽚段颜色与保存在帧缓存的位置的颜色值组合起来
抖动: 抖动可用于最小化因为使用有限精度在帧缓存区中保存颜色值⽽产生的伪像.





3.QOpenGLFunctions

为了保证OpenGL函数调用的正确性,我们需要让我们的GLWidget继承于QOpenGLFunctions,QOpenGLFunctions类的作用是用来提供有保证的OpenGL/ES2.0函数,通常使用OpenGL函数的类需要继承它。随后我们定义了两个着色器类(QOpenGLShader类)的指针m_pVertexShader和m_pFragmentShader。之所以定义为指针是有原因的,上面一篇文章讲述了这些原因。QOpenGLShaderProgram类可以为对象也可以为指针,这依大家的喜好而定。

这段代码,简单地说其实需要五步。首先要通过new运算符在内存中创建空间,然后调用QOpenGLShader::compileSourceCode()函数来将源代码编译成二进制格式,再使用QOpenGLShaderProgram::addShader()函数来装入shader对象,第四步是使用QOpenGLShaderProgram::link()函数来进行链接,最后一步则是将使用QOpenGLShaderProgram::bind()函数将着色