webgl之attribute、uniform和varying

1,229 阅读3分钟

Attribute

定义:attribute变量是一种GLSL ES变量,被用来从外部向顶点着色器内传输数据,只有顶点着色器能使用,只能被声明为全局变量,用来表示“逐顶点”信息,attribute变量的类型智能是float、vec2、vec3、vec4、mat2、mat3和mat4。

声明attribute vec4 a_Position

​ 定义一个attribute变量a_Position,其类型为vec4,后面会单独总结webgl内的变量类型

传值

var a_Position = gl.getAttribLocation(gl.program, 'a_Position'); gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);

​ gl.getAttribLocation()获取attribute变量存储的地址,然后通过gl.vertexAttrib3f()向attribute变量赋值。

gl.getAttribLocation

​ 获取attribute变量存储的地址

gl.vertexAttrib3f的同族函数

gl.vertexAttrib[1|2|3|4]f该系列函数的任务是通过js向顶点着色器中的attribute变量传值,1|2|3|4 分别代表了传输的参数个数。

gl.vertexAttrib1f(location, v0)
gl.vertexAttrib2f(location, v0, v1)
gl.vertexAttrib3f(location, v0, v1, v2)
gl.vertexAttrib4f(location, v0, v1, v2, v3)

同时,可以使用这些方法的矢量版本,它们的名字以"v"结尾,并接受类型化数组

var position = new Float32Array([1.0, 2.0, 3.0, 1.0])
gl.vertexAttrib4fv(a_Position, position)

gl.vertexAttribPointer

​ 上面所说的gl.vertexAttrib[1|2|3|4]f系列函数为attribute变量分配值,但是只能一次向attribute变量分配一个值;如果需要一次性将数组的所有值一次性地分配给一个attribute变量,那么需要怎么做呢

var vertices = new Float32Array([
	0.0, 0.5, -0.5, -0.5, 0.5, -0.5
])
// 创建缓冲区对象
var vertexBuffer = gl.createBuffer()

//绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)

// 向缓冲区写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

// 拿到着色器中的attribute
var a_position = gl.getAttribLocation(program, 'a_Position')

// 用缓冲区的数据(gl.FLOAT) 赋值  a_position
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0)
// a_position变量与对应的 缓冲区对象 建立关联
gl.enableVertexAttribArray(a_position)

Uniform

定义:attribute变量只有顶点着色器才能使用,使用片元着色器,你就需要使用uniform变量,attribute类型只能指定为float型,而uniform变量可以指定为除数组和结构体之外的任意类型。uniform变量可以在顶点着色器和片元着色器中使用,且必须是全局变量,uniform变量包含了“一致”(非逐顶点/逐片元的,各顶点或各片元共用)的数据。比如,变换矩阵就不是逐顶点的,而是所有顶点共用的,所以它在着色器中是uniform变量。

uniform mat4 u_ViewMatrix
uniform vec4 u_LightPosition

声明uniform vec4 u_FragColor

传值

var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor')
gl.uniform4f(u_FragColor, rgba[0], rgba[1], rgba[2], rgba[3])

gl.getUniformLocation

​ 这个函数的功能和参数与gl.getAttribLocation一样,获取uniform变量的地址,但是如果uniform变量不存在或者命名使用了保留字前缀,那么函数返回的是null,而不是-1(gl.getAttribLocation在这种情况下返回的是-1)

gl.uniform4f的同族函数

​ 同gl.vertexAttrib3f的同族函数,同理,gl.uniform[1|2|3|4]f是通过js向着色器中的uniform变量传值。

Varying

定义:varying变量必须事全局变量,它的任务是从顶点着色器向片元着色器传输数据,我们必须在两种着色器中声明同名、同类型的varying变量,和attribute变量一样,varying变量只能是以下类型:float、vec2、vec3、vec4、mat2、mat3和mat4。

声明varying vec2 v_textCoord

使用

var vertexShaderSource = "" +
    "attribute vec4 a_Position;\n" +
    "attribute vec2 a_TexCoord;\n" +
    "varying vec2 v_TexCoord;\n" +
    "void main(){\n" +
    "   gl_Position = a_Position;\n" +
    "   v_TexCoord = a_TexCoord;\n" +
		"}\n";
var fragmentShaderSource = "" + 
    "uniform sampler2D u_Sampler;\n" +
    "varying vec2 v_TexCoord;\n" +
    "void main(){\n" +
    "   gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n" +
    "}\n";
// 将attribute变量a_TexCoord赋值给varying变量v_TexCoord,然后顶点着色器的v_TexCoord去同步片元着色器的v_TexCoord

// 数据缓冲区
var verticesTexCoords = new Float32Array([
  -0.5, 0.5, 0.0, 1.0,
  -0.5, -0.5, 0.0, 0.0, 
  0.5, 0.5, 1.0, 1.0,
  0.5, -0.5, 1.0, 1.0
])
var n = 4
var vertexTexCoordBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer)
gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW)
// 赋值attribute,同步varying
var a_TexCoord = gl.getAttribLocation(program, "a_TexCoord")
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
gl.enableVertexAttribArray(a_TexCoord);