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必须声明成全局变量,数据从着色器外部传递给改变量。

声明格式类型
03 - webgl 笔记 - 通过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变量名
大于等于0attribute变量的地址
-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);

坐标示意图
03 - webgl 笔记 - 通过attribute变量给顶点着色器传值

相关文章: