着色器

着色器

const canvas = document.getElementById("container");
const gl =
  canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 指定清空canvas的颜色
gl.clear(gl.COLOR_BUFFER_BIT); // 清空canvas

使用 WebGL 绘制,依赖于着色器(shader);

  • 顶点着色器(Vertex shader): 绘制每个定点都会调用一次;
  • 片段着色器(Fragment shader): 每个片源(可以简单的理解为像素)都会调用一次;
/**
 * 使用WebGL画点
 * xu.lidong@qq.com
 * */

// 顶点着色器源码
var vertexShaderSrc = `
void main(){
    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);// gl_Position 内置变量,表示点的位置,必须赋值
    gl_PointSize = 10.0;// gl_PointSize 内置变量,表示点的大小(单位像素),可以不赋值,默认为1.0,,绘制单个点时才生效
}`;

// 片段着色器源码
var fragmentShaderSrc = `
void main(){
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);// 内存变量,表示片元颜色RGBA
}`;

// 初始化使用的shader
function initShader(gl) {
  var vertexShader = gl.createShader(gl.VERTEX_SHADER); // 创建顶点着色器
  gl.shaderSource(vertexShader, vertexShaderSrc); // 绑定顶点着色器源码
  gl.compileShader(vertexShader); // 编译定点着色器

  var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); // 创建片段着色器
  gl.shaderSource(fragmentShader, fragmentShaderSrc); // 绑定片段着色器源码
  gl.compileShader(fragmentShader); // 编译片段着色器

  var shaderProgram = gl.createProgram(); // 创建着色器程序
  gl.attachShader(shaderProgram, vertexShader); // 指定顶点着色器
  gl.attachShader(shaderProgram, fragmentShader); // 指定片段着色色器
  gl.linkProgram(shaderProgram); // 链接程序
  gl.useProgram(shaderProgram); //使用着色器
}

function main() {
  var canvas = document.getElementById("container");
  var gl =
    canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  initShader(gl); // 初始化着色器
  gl.clearColor(0.0, 0.0, 0.0, 1.0); // 指定清空canvas的颜色
  gl.clear(gl.COLOR_BUFFER_BIT); // 清空canvas
  gl.drawArrays(gl.POINTS, 0, 1); // 画点
}

向 shader 中传值有两种方式:

  • attribute 变量,传递与顶点相关的数组,只能在顶点着色器中使用;
  • uniform 变量,传递与顶点无关的数据;

前面的代码将点的位置和大小都直接写在了顶点着色器中,现在将其改为由外面的程序传入。首先修改顶点着色器:

const vertexShaderSrc = `
    attribute vec4 a_Position;// 接收传入位置坐标,必须声明为全局
    attribute float a_PointSize;// 接收传入位置坐标,必须声明为全局
    void main(){
        gl_Position = a_Position;// gl_Position 内置变量,表示点的位置,必须赋值
        gl_PointSize = a_PointSize;// gl_PointSize 内置变量,表示点的大小(单位像素),可以不赋值,默认为1.0
    }
`;

然后在 initShader 的最后给这两个变量赋值:

// 获取shader中的a_Position变量
vaconstr a_Position = gl.getAttribLocation(shaderProgram, 'a_Position');
// 给变量a_Position赋值
gl.vertexAttrib4f(a_Position, 0.0, 0.0, 0.0, 1.0);

// 获取shader中的a_PointSize变量
vaconstr a_PointSize = gl.getAttribLocation(shaderProgram, 'a_PointSize');
// a_PointSize
gl.vertexAttrib1f(a_PointSize, 10.0);