着色器语言三种变量 attribute、uniform 和 varying)

优质
小牛编辑
128浏览
2023-12-01

着色器语言和C语言一样,通过一个表示特定数据类型的关键词声明一个变量,比如int num;通过int关键字声明一个整数型变量num,不过着色器语言还提供了三个关键字attributeuniformvarying用来声明特定用途的变量。

attributeuniform关键字的目的主要是为了javascript语言可以通过相关的WebGL API把一些数据传递给着色器,如果一个着色器中一个变量,着色器代码中变量不通过attributeuniform声明标识,该变量是不能从javascript代码中获得相应的数据。

关键字(变量类型)数据传递声明变量
attributejavascript——>顶点着色器声明顶点数据变量
uniformjavascript——>顶点、片元着色器声明非顶点数据变量
varying顶点着色器——>片元着色器声明需要插值计算的顶点变量

attribute类型变量

attribute关键字通常用来声明与顶点数据相关的变量,比如顶点位置坐标数据、顶点颜色数据、顶点法向量数据...

顶点着色器中通过attribute关键字声明的顶点变量,javascript代码可以通过相关的WebGL API把顶点的数据传递给着色器中相应的顶点变量。

因为javascript没必要给片元着色器传递顶点数据,所以规定attribute关键字只能在顶点着色器中声明变量使用。只要注意attribute关键字声明顶点变量代码位于主函数main之外就可以。

// attribute声明顶点位置变量
attribute vec4 position;
// attribute声明顶点颜色变量
attribute vec4 a_color;
// attribute声明顶点法向量
attribute vec4 normal;
// 与顶点相关的浮点数
attribute float scale;

同一个顶点着色器通常需要处理是一批顶点数据,一个顶点可能会有多种数据,比如顶点位置、颜色、法向量,还有其它自定义的,比如attribute float scale;,声明了一个scale变量。

// attribute声明顶点位置变量
attribute vec4 position;
// 与顶点相关的浮点数
attribute float scale;
void main() {
  // 每个顶点的x坐标乘以该顶点对应的一个系数scale
  gl_Position = vec4(position.x*scale,position.y,position.z,1.0);
}

uniform类型变量

uniform关键字出现的目的就是为了javascript可以通过相关的WebGL API给着色器变量传递数据,比如传递一个光源的位置数据、一个光源的方向数据、一个光源的颜色数据、一个用于顶点变换的模型矩阵、一个用于顶点变换的视图矩阵...

不过要注意如果是顶点相关的变量,比如顶点位置、顶点颜色等顶点数据相关变量不能使用关键字uniform去声明,主要是顶点的数据往往不是一个,通常有很多个顶点,而且这些顶点都要逐顶点执行main函数中的程序,所以为了声明顶点数据相关的变量,着色器语言规定了一个新的关键字attribute

javascript可以给顶点着色器的变量传递数据,也可以给片元着色器的变量传递数据,也就是说uniform关键字既可以在顶点着色器中使用,也可以在片元着色器中使用。只要注意uniform关键字声明变量需要在主函数main之前声明。

varying类型变量

attribute vec4 a_color;在顶点着色器中声明了一个顶点颜色变量,如果想在片元着色器中获得顶点颜色插值计算以后的数据,需要同时在顶点着色器和片元着色器中执行varying vec4 v_color;,也就是在顶点、片元两个着色器代码中都需要通过关键字varying声明一个新变量v_color,最后再顶点着色器中执行v_color = a_color;即可

顶点着色器

attribute vec4 a_color;// attribute声明顶点颜色变量
varying vec4 v_color;//varying声明顶点颜色插值后变量
void main() {
  //顶点颜色插值计算
  v_color = a_color;
}

片元着色器

// 接收顶点着色器中v_color数据
varying vec4 v_color;
void main() {
  // 插值后颜色数据赋值给对应的片元
  gl_FragColor = v_color;
}

varying类型变量主要是为了完成顶点着色器和片元着色器之间的数据传递和插值计算。比如在一个WebGL程序中通过三个顶点绘制一个彩色三角形,三个顶点的位置坐标定义了一个三角形区域,这个三角形区域经过片元着色器处理后会得到由一个个片元或者说像素组成的三角形区域,在片元化的过程中,顶点的颜色数据也会进行插值计算,插值计算之前每个顶点对应一个颜色,插值计算之后,每个片元对应一个颜色值,通过varying关键字就可以在片元着色器中获得插值后的颜色数据,然后赋值给片元。

<!-- 顶点着色器源码 -->
<script id="vertexShader" type="x-shader/x-vertex">
  //attribute声明vec4类型变量apos
  attribute vec4 apos;
  // attribute声明顶点颜色变量
  attribute vec4 a_color;
  //varying声明顶点颜色插值后变量
  varying vec4 v_color;
  void main() {
    // 顶点坐标apos赋值给内置变量gl_Position
    gl_Position = apos;
    //顶点颜色插值计算
    v_color = a_color;
  }
</script>
<!-- 片元着色器源码 -->
<script id="fragmentShader" type="x-shader/x-fragment">
  // 所有float类型数据的精度是lowp
  precision lowp float;
  // 接收顶点着色器中v_color数据
  varying vec4 v_color;
  void main() {
    // 插值后颜色数据赋值给对应的片元
    gl_FragColor = v_color;
  }
</script>