有两种方式可以通过js
程序向着色器传递数据
- 通过 attribute变量 – 传输的是与顶点相关的数据;
- 通过 uniform变量 – 传输的是对所有顶点都相同或者与顶点无关的数据;
通过上一个程序,在webgl
中绘制了一个顶点,但是顶点的位置不能通过js
程序来控制,下面通过js
给顶点着色器传递数据来控制顶点的位置。
1、在顶点着色器中生命 attribute 变量
// 顶点着色器
// 声明一个 attribute 变量 类型是 vec4
attribute vec4 a_Position;
void main(){
}
2、将 attribute 变量赋值给 gl_Position
// 顶点着色器
// 声明一个 attribute 变量 类型是 vec4
attribute vec4 a_Position;
void main(){
// 将声明的变量赋值给gl内置的变量
gl_Position = a_Position;
// 设置顶点的大小单位是像素
gl_PointSize = 10.0;
}
3、通过 js 向 attribute 变量传值
// 获取 attribute 变量 a_Position 的存储地址
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
// 创建一个类型话数组
var positions = new Float32Array([0.5, 0.0, 0.0, 1.0]);
// 将顶点位置传递给 attribute 变量
gl.vertexAttrib4fv(a_Position,positions);
通过以上三个步骤就实现了,通过js
向webgl
着色器传递数据
1、存储限定符
上面代码中的 attribute vec4 a_Position;
关键词 attribute 是存储限定符,表示接下来的声明的变量是一个attribute
变量
注意:attribute变量必须声明为全局变量
变量的声明格式
格式 | 示例 |
---|---|
<存储限定符><类型><变量名>; | attribute vec a_Position; |
2、获取变量的存储位置
着色器代码中每个变量都有一个 存储地址,以便于通过 存储地址向变量传输数据
获取 attribute 变量 存储地址的方法是,挂载在gl
对象上的 ()
方法
该方法的第一个参数是一个程序对象 ,包含了顶点着色器和片元着色器
第二个参数是想要获存储地址的 attribute变量的名称字符串
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
返回值是一个存储地址
变量名 | 参数 | 返回值 |
---|---|---|
(program, name) |
program:程序对象 ,name:变量名称
|
大于等于0是:拿到地址 ,-1:变量不存在
|
3、向变量赋值
// 向顶点位置传输数据
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
**gl.vertexAttrib3f(location, v0, v1, v2)**是将数据(v0, v1, v2)传给有location
指定的attribute
变量
4、gl.vertexAttrib3f()的同族方法
gl.vertexAttrib1f(location, v0)
gl.vertexAttrib2f(location, v0, v1)
gl.vertexAttrib3f(location, v0, v1, v2)
gl.vertexAttrib4f(location, v0, v1, v2, v3)
以上系列方法的主要任务就是将数据从js
传输给attribute
变量,以上每个方法都有一个矢量
版本,上面的是以 f结尾,矢量版本是以 v结尾,并且可以接受一个类型化数组
/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
// 创建一个类型话数组
var positions = new Float32Array([0.5, 0.0, 0.0, 1.0]);
// 将顶点位置传递给 attribute 变量
gl.vertexAttrib4fv(a_Position,positions);
既然可以通过js
程序改变顶点的位置,那么也可以改变大小
顶点着色器
// 声明 attribute 变量 传递顶点位置
attribute vec4 a_Position;
// 声明 attribute 变量 传递顶点大小
attribute float a_PointSize;
void main(){
gl_Position = a_Position;
gl_PointSize = a_PointSize;
}
获取存储地址并传值
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
var a_PointSize = gl.getAttributLocation(gl.program, 'a_PointSize');
// 传递顶点位置
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
// 传递顶点大小
gl.vertexAttrib1f(a_PointSize, 10.0);
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通过 attribute 向着色器传递数据</title>
<link rel="stylesheet" href="../css/">
</head>
<body>
<canvas id="webgl" width="512" height="512"></canvas>
</body>
<script src="../lib/"></script>
<script src="../lib/"></script>
<script src="../lib/"></script>
<script>
(function () {
// 获取canvas对象
var canvas = document.getElementById('webgl');
// 获取webgl 上下文对象
var gl = getWebGLContext(canvas);
// 顶点着色器
var vertex_shader_source = '' +
'attribute vec4 a_Position;' +
'void main() {' +
' gl_Position = a_Position;' +
' gl_PointSize = 10.0;' +
'}';
// 片元着色器
var fragment_shader_source = '' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' +
'}';
// 初始化着色器
if (!initShaders(gl, vertex_shader_source, fragment_shader_source)) {
console.log('初始化着色器失败!');
return false;
}
// 获取 attribute 变量 a_Position 的存储地址
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('获取 a_Position 变量地址失败!');
return false;
}
// 将顶点位置传递给 attribute 变量
// gl.vertexAttrib1f(a_Position, -0.5);
// gl.vertexAttrib2f(a_Position, -0.5, -0.5);
// gl.vertexAttrib3f(a_Position, -0.5, -0.5, 0.0);
// gl.vertexAttrib4f(a_Position, -0.5, -0.5, 0.0, 1.0);
var positions = new Float32Array([0.5, 0.0, 0.0, 1.0]);
gl.vertexAttrib4fv(a_Position, positions);
// 指定需要清除的颜色
gl.clearColor(0.0, 0.5, 0.5, 1.0);
// 清除颜色
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);
}());
</script>
</html>
uniform
1、存储限定符
向顶点着色器中传递数据是通过 attribute,向片元着色器中传递数据就需要使用 uniform声明变量,uniform变量传递的数据是一致的不变的数据例如所有的颜色应用的都是这个变量但是所有点的位置是不一样的,而 attribute传递的数据是变化的。
uniform和 attribute一样都是存储限定符;
2、获取存储地址
通过方法 (program, name)
可以获取 uniform变量的存储地址
功能和(ptogram, name)
一样,注意如果变量不存在或者使用保留字此时**(program, name)**
返回的是 null不是 -1.
3、gl.uniform4f()同族方法
和gl.vertexAttribute3f()
基本一样
示例代码
// 声明 uniform 变量 储存颜色值
uniform vec4 u_FragColor;
void main(){
// 将uniform 变量赋值
gl_FragColor = u_FragColor;
}
// 获取 uniform 变量
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
// 赋值
gl.uniform4f(u_FragColor, 0.0, 1.0, 0.0, 1.0);