欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))

程序员文章站 2022-05-23 14:02:31
...

这一节的目标是,在上一节用鼠标点击画点的基础上增加改变颜色的功能,点的颜色取决于其位置。

结果:
【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))


可以用 uniform 变量将颜色值传给着色器,其步骤与用 attribute 变量传递的类似。不同的仅仅是,这次数据传输的目标是片元着色器,而非顶点着色器:

  1. 在片元着色器中准备 uniform 变量。
  2. 用这个 uniform 变量向 gl_FragColor 赋值。
  3. 将颜色数据从JS传给该 uniform 变量。

示例程序 ColoredPoints.js

//顶点着色器程序
var VSHADER_SOURCE =
    'attribute vec4 a_Position;'+
    'void main(){'+
    'gl_Position=a_Position;'+
    'gl_PointSize=10.0;'+
    '}';

//片元着色器程序
var FSHADER_SOURCE=
    'precision mediump float;'+
    'uniform vec4 u_FragColor;'+
    'void main(){'+
    'gl_FragColor = u_FragColor;'+
    '}';

function main() {
    //获取canvas元素
    var canvas = document.getElementById("webgl");
    if(!canvas){
        console.log("Failed to retrieve the <canvas> element");
        return;
    }

    //获取WebGL绘图上下文
    var gl = getWebGLContext(canvas);
    if(!gl){
        console.log("Failed to get the rendering context for WebGL");
        return;
    }

    //初始化着色器
    if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
        console.log("Failed to initialize shaders.");
        return;
    }

    //获取a_Position变量存储位置
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');

    if(a_Position < 0){
        console.log("Failed to get the storage location of a_Position");
        return;
    }

    //获取u_FragColor 变量存储位置
    var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');

    if(!u_FragColor){
        console.log('Failed to get the storage location of u_FragColor');
        return;
    }

    canvas.onmousedown = function(ev){
        click(ev,gl,canvas,a_Position,u_FragColor);
    };

    //指定清空<canvas>颜色
    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    //清空<canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);
}

var g_points = [];
var g_colors = [];
function click(ev, gl, canvas, a_Position,u_FragColor){
    var x= ev.clientX;
    var y = ev.clientY;
    var rect = ev.target.getBoundingClientRect();
    x = ((x - rect.left) - canvas.width / 2) / (canvas.width / 2);
    y = (canvas.height / 2 - (y - rect.top)) / (canvas.height / 2);
    //将坐标存储到g_points数组中
    g_points.push([x, y]);
    if(x >= 0.0 && y >= 0.0){  //第一象限
        g_colors.push([1.0, 0.0, 0.0, 1.0]);  //红色
    }else if(x < 0.0 && y < 0.0){  //第三象限
        g_colors.push([0.0, 1.0, 0.0, 1.0]);  //绿色
    }else{
        g_colors.push([1.0, 1.0, 1.0, 1.0]);  //白色
    }

    //清除<canvas>
    gl.clear(gl.COLOR_BUFFER_BIT);

    var len = g_points.length;
    for(var i = 0; i < len; i++){
        var xy=g_points[i];
        var rgba = g_colors[i];

        //将点的位置传递到a_Position变量中
        gl.vertexAttrib3f(a_Position, xy[0], xy[1], 0.0);
        //将点的颜色传递到u_FragColor变量中
        gl.uniform4f(u_FragColor, rgba[0],  rgba[1], rgba[2], rgba[3]);

        //绘制点
        gl.drawArrays(gl.POINTS, 0, 1);
    }
}

uniform 变量

只有顶点着色器才能使用 attribute 变量,使用片元着色器时,你就需要使用 uniform 变量。

在使用 uniform 变量之前,首先需要按照与声明 attribute 变量相同的格式<存储限定符><类型><变量名>来声明 uniform 变量。

【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))

在例子中, uniform 变量 u_FragColor 被赋值给 gl_FragColor 变量。向 uniform 变量传数据的方式向 attribute 变量传数据相似:首先获取变量的存储地址,然后再JS程序中按照地址将数据传递过去。

//片元着色器程序
var FSHADER_SOURCE=
    'precision mediump float;'+
    'uniform vec4 u_FragColor;'+
    'void main(){'+
    'gl_FragColor = u_FragColor;'+
    '}';

这一行使用精度限定词来制定变量的范围和精度,本例中为中度精度,后面第5章会详细讲。

'precision mediump float;'+

获取 uniform 变量的存储地址

    //获取u_FragColor 变量存储位置
    var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');

    if(!u_FragColor){
        console.log('Failed to get the storage location of u_FragColor');
        return;
    }

可以使用以下方法来获取 uniform 变量的存储地址

【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))


向 uniform 变量赋值

有了 uniform 变量的存储地址,就可以使用 gl.uniform4f()向变量中写入数据。该函数的功能和参数与 gl.vertexAttrib[1234]f()相似。

【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))


gl.uniform4f()的同族函数

gl.uniform4f()也有一系列同族函数。

【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))


结果:
【笔记】《WebGL编程指南》学习-第2章WebGL入门(6-改变点的颜色))