在上一篇文章中,更改shader中的数值,会让图形的大小和颜色进行改变。要进行复杂的设计,必然数据之间会进行传递,就涉及到shader里面的三种变量类型uniform,attribute和varying的认知。本文先了解下这三种类型,然后尝试下在shader中如何传值。
首先字面翻译这三种类型☺
attribute:属性;特征;性质
uniform:一致的,统一的
varing:变化的
1、shader的传值方式
1.1 attribute
attribute变量是只能在vertex中使用
当使用 Vertex Shader 时,它的代码将作用于几何体的每个顶点。在每个顶点之间,有些数据会发生变化,这类数据称为 attribute。
attribute:使用顶点数组封装每个顶点的数据,一般用于每个顶点都各不相同的变量,如顶点的位置。
1.2 uniform
uniform可以在vertex和fragment共享使用
当使用 Vertex Shader 时,它的代码将作用于几何体的每个顶点。有些数据在顶点之间永远不会变化,称这种数据为 uniform。
uniform:顶点着色器使用的常量数据,不能被修改,一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的变量,如当前光源的位置。
uniform变量在vertex和fragment两者之间声明方式完全一样,可以在vertex和fragment共享使用。相当于一个被vertex和fragment shader共享的全局变量。
uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。
1.3 varing
varying变量是vertex和fragment之间做数据传递用的
Fragment Shader 在 Vertex Shader 之后执行,它的作用是为几何体的每个可见像素进行着色。我们可以通过uniforms 将数据发送给它,也可以将 Vertex Shader 中的数据发送给它,我们将这种从 Vertex Shader 发送到 Fragment Shader 的数据称为 varying。
Fragment Shader 中最直接的指令就是可以使用相同的颜色为所有像素进行着色。如果只设置了颜色属性,就相当于得到了与 MeshBasicMaterial 等价的材质。如果我们将光照的位置发送给 Fragment Shader,然后根据像素收到光照影响的多少来给像素上色,此时就能得到与 MeshPhongMaterial 效果等价的材质。
varying: 从顶点着色器vertex发送到片元着色器Fragment中的插值计算数据
import initShaders from '../initShaders.js'
let canvas = document.getElementById('webgl')
let gl = canvas.getContext('webgl')
// vertexShader, fragmentShader
let vertexShader = `
attribute vec2 a_position;//attribute只能在这顶点着色器中声明
uniform float u_size;//在这里声明尺寸变量,赋值后,不会被改变
varying vec2 v_xx;//在片元着色器中会接受该变量赋予的值
void main() {
v_xx = a_position;
gl_Position = vec4(a_position, 0.0, 1.0);
gl_PointSize = u_size;
}
`
let fragmentShader = `
precision mediump float;
varying vec2 v_xx;//用于接收上述顶点着色器中的变量
uniform vec3 u_color;//声明颜色变量
void main() {
gl_FragColor = vec4(v_xx, 0.0, 1.0);
}
`
initShaders(gl,vertexShader,fragmentShader)
// 清空canvas画布
gl.clearColor(0.0,0.0,0.0,1.0) // rgba()
gl.clear(gl.COLOR_BUFFER_BIT)
//Attribute将js中的数据传给vertexShader
let a_position = gl.getAttribLocation(gl.program,'a_position')
gl.vertexAttrib2f(a_position,0.2,0.8)
//Uniform 给fragmentShader中声明的变量u_color赋值
let u_color = gl.getUniformLocation(gl.program,'u_color')
gl.uniform3f(u_color,0.0,1.0,0.0)
//Uniform 给vertexShader中声明的变量u_size赋值
let u_size = gl.getUniformLocation(gl.program,'u_size')
gl.uniform1f(u_size,55.0)
// 画一个点
gl.drawArrays(gl.POINTS,0,1)
这个例子的运行结果如图所示:
具体的使用看代码中的注释部分。
后面八青妹的矩阵变换例子中就使用到了uniform 变量,多用几次,就感受到了他们之间的区别。总而言之,还是得多用,多多练习。