1、着色器传值
通过JavaScript给着色器传值,有两种方式
- 方式一:attribute变量,传输的是那些鱼顶点相关的数据。
- 方式二:uniform变量,传输的是对于所有顶点都相同或者与顶点无关的数据。
2、传值步骤
使用attribute变量像着色器传递数据步骤:
- 1、在顶点着色器中声明 attribute 变量;
- 2、将 attribute 变量赋值给 gl_Position 变量;
- 3、向 attribute 变量传输数据;
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通过 attribute 向着色器传递数据</title>
<link rel="stylesheet" href="../css/common.css">
</head>
<body>
<canvas id="webgl" width="512" height="512"></canvas>
</body>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></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>
效果
示例链接1-通过 attribute 给顶点着色器传递数据
2.1、代码分析
1、声明 attribute 变量
attribute vec4 a_Position;
attribute是存储限定符表示接下来的变量是一个attribute变量
attribute必须声明成全局变量,数据从着色器外部传递给改变量。
声明格式类型
2、获取attribute 变量存储位置
// 获取 attribute 变量 a_Position 的存储地址
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('获取 a_Position 变量地址失败!');
return false;
}
通过initShaders初始化着色器之后,webgl会辨识出着色器具有attribute变量,每个变量都具有一个存储地址,通过存储地址可以传递数据。
使用webgl上下文对象具有的方法gl.getAttribLocation()就可以获取变量的地址。
| 方法名 | 参数 | 返回值 |
|---|---|---|
gl_getAttribLocation(gl.program, name) |
pargram:指包含顶点着色器和片元着色器的着色器程序name:要获取器存储地址的attribute变量名 |
大于等于0:attribute变量的地址-1:指定的变量不存在或者其命名具有 gl_和webgl_前缀 |
3、向attribute 变量赋值
// 将顶点位置传递给 attribute 变量
gl.vertexAttrib3f(a_Position, -0.5, 0.5, 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)
上面方法的作用都是将数据局传递给
location参数指定的attribute变量,以上方法的矢量版本(以v–vector)结尾的,可以接受一个类型化数组。
var positions = new Float32Array([1.0, 2.0, 3.0, 1.0]);
gl.vertexAttrib4fv(a_Position, positions);
3、通过鼠标点击绘制点
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通过鼠标点击绘制点</title>
<link rel="stylesheet" href="../css/common.css">
</head>
<body>
<canvas id="webgl" width="512" height="512"></canvas>
</body>
<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></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;
}
// 注册 canvas 点击事件
canvas.onclick = function (ev) {
click(ev, gl, canvas, a_Position);
};
// 指定需要清除的颜色
gl.clearColor(0.0, 0.5, 0.5, 1.0);
// 清除颜色
gl.clear(gl.COLOR_BUFFER_BIT);
// 点数组
var g_points = [];
function click(ev, gl, canvas, a_Position) {
console.log(ev);
// 鼠标点击位置坐标--浏览器客户区中的坐标
var client_x = ev.clientX;
var client_y = ev.clientY;
// 获取canvas 边界框矩形值
var rect = ev.target.getBoundingClientRect();
// canvas范围内坐标
var canvas_x = client_x - rect.left;
var canvas_y = client_y - rect.top;
// webgl系统坐标
var gl_x = (canvas_x - canvas.width / 2) / (canvas.width / 2);
var gl_y = (canvas.height / 2 - canvas_y) / (canvas.height / 2);
// 存储坐标到数组
g_points.push(gl_x, gl_y);
// 清空canvas
gl.clear(gl.COLOR_BUFFER_BIT);
var len = g_points.length;
for (var i = 0; i < len; i += 2) {
// 将点的位置传递到 attribute 变量
gl.vertexAttrib2f(a_Position, g_points[i], g_points[i+1]);
// 绘制点
gl.drawArrays(gl.POINTS, 0, 1);
}
}
}());
</script>
</html>
效果
示例链接2-通过鼠标点击绘制点
3.1、代码分析
示例仅仅是动态获取了鼠标点击的位置,将点击位置坐标转换为webgl系统坐标,然后循环绘制。
注册点击事件
// 注册 canvas 点击事件
canvas.onclick = function (ev) {
click(ev, gl, canvas, a_Position);
};
获取 webgl 系统坐标
// 鼠标点击位置坐标--浏览器客户区中的坐标
var client_x = ev.clientX;
var client_y = ev.clientY;
// 获取canvas 边界框矩形值
var rect = ev.target.getBoundingClientRect();
// canvas范围内坐标
var canvas_x = client_x - rect.left;
var canvas_y = client_y - rect.top;
// webgl系统坐标
var gl_x = (canvas_x - canvas.width / 2) / (canvas.width / 2);
var gl_y = (canvas.height / 2 - canvas_y) / (canvas.height / 2);
// 存储坐标到数组
g_points.push(gl_x, gl_y);
坐标示意图