OpenGL-着色器

OpenGL渲染架构

在这里插入图片描述

组成模块

OpenGL中的渲染架构主要分为两个模块

  • Client: 上层代码和OpenGL API方法,这部分在CPU中运行。
  • Server: OpenGL底层的渲染处理,这部分在GPU中运行。

流程

  • 上层代码通过调用OpenGL API中的方法,将图形渲染的相关数据以通道的形式传递到服务器中顶点着色器和片元着色器,并交由GPU处理。
  • 服务器接收到通道传递的数据,交由相应着色器进行渲染处理,并将最终的结果渲染到屏幕上。
  • 这个过程中,顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)两个部分是可以使用GLSL语言自定义编程的,其他部分由OpenGL底层控制,无法修改。

数据通道

从图上我们可以看出,客户端和服务器进行数据传递的通道有三种

  1. Attributes

    只能将数据直接传递到顶点着色器,但可以通过GLSL语言间接传入片元着色器中。多用来传递经常发生变动的数据,例如:纹理坐标、光照法线、顶点坐标、颜色数据、投影矩阵、模型矩阵等。

  2. Uniform

    可以将数据直接传递到顶点着色器和片元着色器。多用来传递不经常发生变动的数据。例如:旋转矩阵、视频的颜色控件YUV数据。

  3. Texture Data

    可以将纹理数据直接传递到顶点着色器和片元着色器。由于纹理数据是在片元着色器中进行,所以Texture Data通道一般情况下都是将纹理数据传递到片元着色器,传入顶点着色器并没有什么意义。

着色器(Shader)

Shader其实就是一段执行在GPU上的程序,此程序使用OpenGL ES SL语言来编写。它是一个描述顶点或像素特性的简单程序。在OpenGL ES中常用的shader有两种:vertex shader和fragment shader。Geometry Shader(几何着色器)是继Vertex Shader和Fragment Shader之后,由Shader Model 4引入的新的着色器。还有一个compute Shader由Shader Model 5引入的提供通用计算能力的着色器。

不同阶段的着色器可以对应不同版本的GLSL。

在这里插入图片描述

可编程着色器简介

一、顶点着色器(Vertex Shader)

对于发送给GPU的每一个Vertex(顶点),都要执行一次Vertex Shader。其功能是把每个顶点在虚拟空间中的三维坐标变换为可以在屏幕上显示的二维坐标,并带有用于z-buffer的深度信息。Vertex Shader可以操作的属性有:位置、颜色、纹理坐标,但是不能创建新的顶点。

vertex shader主要完成以下工作:
  1. 基于点操作的矩阵乘法位置变换。
  2. 根据光照公式计算每点的颜色值。
  3. 生成或者转换纹理坐标。
Vertex Shader输入数据如下:
  1. Attributes: 由 vertext array 提供的顶点数据,如空间位置,法向量,纹理坐标以及顶点颜色,它是针对每一个顶点的数据。属性只在顶点着色器中才有,片元着色器中没有属性。属性可以理解为针对每一个顶点的输入数据。OpenGL ES 2.0 规定了所有实现应该支持的最大属性个数不能少于 8 个。

    注:Vertex Attributes 是每点的属性数据。与一个index序号绑定。外部程序可通过 glBindAttribLocation将一个attribute 名与一个index绑定起来。当然,OPENGL ES 内部会自动绑定所有attributes.外部程序只需通过 glGetAttribLocation获取指定attribute名的index。 给Attribute传值可以通过 glVertexAttribPointer函数或者glVertexAttrib4fv。

  2. Uniforms: uniforms保存由应用程序传递给着色器的只读常量数据。在顶点着色器中,这些数据通常是变换矩阵,光照参数,颜色等。由 uniform 修饰符修饰的变量属于全局变量,该全局性对顶点着色器与片元着色器均可见,也就是说,这两个着色器如果被连接到同一 个program Object,则它们共享同一份 uniform 全局变量集。因此如果在这两个着色器中都声明了同名的 uniform 变量,要保证这对同名变量完全相同:同名+同类型,因为它们实际是同一个变量。此外,uniform 变量存储在常量存储区,因此限制了 uniform 变量的个数,OpenGL ES 2.0 也规定了所有实现应该支持的最大顶点着色器 uniform 变量个数不能少于 128 个,最大的片元着色器 uniform 变量个数不能少于 16 个。

  3. Samplers: 一种特殊的 uniform,在vertex shader中是可选的,用于呈现纹理。sampler 可用于顶点着色器和片元着色器。

  4. Shader program: 由 main 声明的一段程序源码,描述在顶点上执行的操作:如坐标变换,计算光照公式来产生 per-vertex 颜色或计算纹理坐标。

Vertex Shader输出为:
  • Varying: varying 变量用于存储顶点着色器的输出数据,当然也存储片元着色器的输入数据,varying 变量最终会在光栅化处理阶段被线性插值。顶点着色器如果声明了 varying 变量,它必须被传递到片元着色器中才能进一步传递到下一阶段,因此顶点着色器中声明的 varying 变量都应在片元着色器中重新声明同名同类型的 varying 变量。OpenGL ES 2.0 也规定了所有实现应该支持的最大 varying 变量个数不能少于 8 个。
  • 在顶点着色器阶段至少应输出位置信息-即内建变量:gl_Position,是每个点固有的Varying,表示点的空间位置。其它两个可选的变量为:gl_FrontFacing 和 gl_PointSize。

二、片元着色器(Fragment Shader)

Pixel Shader(像素着色器)就是众所周知的Fragment Shader(片元着色器),它计算每个像素的颜色和其它属性。它通过应用光照值、凹凸贴图,阴影,镜面高光,半透明等处理来计算像素的颜色并输出。它也可改变像素的深度(z-buffering)或在多个渲染目标被激活的状态下输出多种颜色。一个Pixel Shader不能产生复杂的效果,因为它只在一个像素上进行操作,而不知道场景的几何形状。

Fragment Shader输入数据如下:
  1. Varyings: 这个在前面已经讲过了,顶点着色器阶段输出的 varying 变量在光栅化阶段被线性插值计算之后输出到片元着色器中作为它的输入,即上图中的 gl_FragCoord,gl_FrontFacing 和 gl_PointCoord。OpenGL ES 2.0 也规定了所有实现应该支持的最大 varying 变量个数不能少于 8 个。
  2. Uniforms: 前面也已经讲过,这里是用于片元着色器的常量,如雾化参数,纹理参数等;OpenGL ES 2.0 也规定了所有实现应该支持的最大的片元着色器 uniform 变量个数不能少于 16 个。
  3. Samples: 一种特殊的 uniform,用于呈现纹理。
  4. Shader program: 由main申明的一段程序源码,描述在片元上执行的操作。
FragmentShader输出为:

在顶点着色器阶段只有唯一的 varying 输出变量-即内建变量:gl_FragColor。

三、曲面细分着色器

可选着色器。包括曲面细分控制着色(TCS,Tessellation Control Shader)和曲面细分评估着色(TES,Tessellation Evaluation Shader)。

TCS作用于一组叫做控制点(CP,Control Points)的顶点组。控制点并不是被定义成像三角形、矩形、五边形等多边形形式,而是定义为一个几何表面,这个表面通常由多项式来定义,而且移动其中一个控制点将会影响整个表面。这个通常在一些图形软件中,用户可以通过移动一组控制点来随意改变模型表面或者曲线形状,一组控制点通常称为一个Patch。

顶点着色与片元着色在编程上的差异

  1. 精度: 着色语言定了三种级别的精度:lowp, mediump, highp。我们可以在 glsl 脚本文件的开头定义默认的精度。如下代码定义在 float 类型默认使用 highp 级别的精度
    precision highp float;
    在顶点着色阶段,如果没有用户自定义的默认精度,那么 int 和 float 都默认为 highp 级别;而在片元着色阶段,如果没有用户自定义的默认精度,那么就真的没有默认精度了,我们必须在每个变量前放置精度描述符。此外,OpenGL ES 2.0 标准也没有强制要求所有实现在片元阶段都支持 highp 精度的。我们可以通过查看是否定义 GL_FRAGMENT_PRECISION_HIGH 来判断具体实现是否在片元着色器阶段支持 highp 精度,从而编写出可移植的代码。当然,通常我们不需要在片元着色器阶段使用 highp 级别的精度,推荐的做法是先使用 mediump 级别的精度,只有在效果不够好的情况下再考虑 highp 精度。
  2. attribute: 修饰符只可用于顶点着色。这个前面已经说过了。
  3. invariant: 或由于精度的不同,或因为编译优化的原因,在顶点着色和片元着色阶段同样的计算可能会得到不同的结果,这会导致一些问题(z-fighting)。因此 glsl 引入了 invariant 修饰符来修饰在两个着色阶段的同一变量,确保同样的计算会得到相同的值。

OpenGL ES着色语言是两种紧密关联的语言。这些语言用来在OpenGL ES处理管线的可编程处理器创建着色器。 在本文档中,除非另外说明,一个语言功能适用于所有语言,并且通用用法将把他们当做一个语言来看待。特定语言将指出它们的目标处理器:顶点(vertext)或片元(fragment)。

任何被着色器使用的OpenGL ES状态值都会自动地被跟踪并且作用于着色器上。这个自动状态跟踪机制允许应用程序为状态管理而使用OpenGL ES状态命令,并且这些状态值自动地应用在着色器上。

固定着色器简介

固定着色器是一些系统封装好的非可编程着色器

初始化着色器管理器

//没有着色器,在OpenGL 核心框架中是无法进行任何渲染的。初始化一个渲染管理器。
GLShaderManager shaderManager = shaderManager.InitializeStockShaders();

选择着色器类型

// Use a stock shader, and pass in the parameters needed

GLint UseStockShader(GLT_STOCK_SHADER nShaderID, ...);
1.单元着色器
shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);

参数1: 固定着色器种类 - 单元着色器。

参数2: 颜色。

使⽤场景: 绘制默认OpenGL 坐标系(-1,1)下图形,图形所有⽚段都会以⼀种颜⾊填充。只能绘画一些图形,如三角形、矩形等,对于平移、缩放等形状变化无能为力。

2.平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLflfloat mvp[16],GLflfloat vColor[4]);

参数1: 固定着⾊器种类 - 平⾯着⾊器。

参数2: 允许变化的4*4矩阵。

参数3: 颜色。

使⽤场景: 在绘制图形时, 可以应⽤变换(模型/投影变化)。使用最多的固定着色器。

3.上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLflfloat mvp[16]);

参数1: 固定着色器种类 - 上色着色器。

参数2: 允许变化的4*4矩阵。

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),颜色将会平滑的插入到顶点之间称为平滑着色。

4.默认光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vColor[4]);

参数1: 固定着色器种类 - 默认光源着色器。

参数2: 模型4*4矩阵。

参数3: 投影4*4矩阵。

参数3: 颜色值。

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。

5.点光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vLightPos[3],GLflfloat vColor[4]); 

参数1: 固定着色器种类 - 点光源着色器。

参数2: 模型4*4矩阵。

参数3: 投影4*4矩阵。

参数4: 点光源的位置

参数5: 颜色值。

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。它与默认光源着色器非常类似,区别只是光源位置可以是特定的。

6.纹理替换矩阵着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLflfloat mvMatrix[16],GLint nTextureUnit);

参数1: 固定着色器种类 - 纹理替换矩阵着色器。

参数2: 模型4*4矩阵。

参数3: 纹理单元。

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,使用纹理单元来进行颜色填充,其中每个像素点的颜色是从纹理中获取。

7.纹理调整着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLflfloat mvMatrix[16],GLflfloat vColor[4],GLint nTextureUnit);

参数1: 固定着色器种类 - 纹理调整着色器。

参数2: 模型4*4矩阵。

参数3: 颜色值

参数4: 纹理单元。

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,着色器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理,将颜色与纹理进行颜色混合后才填充到片段中。

8.纹理光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLflfloat mvMatrix[16],GLflfloat pMatrix[16],GLflfloat vLightPos[3],GLflfloat vBaseColor[4],GLint nTextureUnit);

参数1: 固定着色器种类 - 纹理光源着色器。

参数2: 模型4*4矩阵。

参数3: 投影4*4矩阵。

参数4: 点光源的位置。

参数5: 颜色值(几何图形的基本色)。

参数6: 纹理单元

使用场景: 在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵,着色器将一个纹理通过漫反射照明计算进行调整(相乘)。是一个中和了纹理、光源、颜色的综合性着色器。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值