WebGL

博客分类: 江河计划

WebGL

算法

二叉搜索树中第K小的元素

给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。

说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。

示例 1:

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 1
function sortArr(arr, num){
    for(let i=0; i<arr.length; i++){
        if(arr[i] > num){
            arr.splice(i, 0, num);
            return
        }
    }
    arr.push(num);
}
var kthSmallest = function(root, k) {
    if(!root) return null;
    var arr = [];
    var stack = [];
    stack.push(root)
    while(stack.length){
        var node = stack.pop();
        sortArr(arr, node.val);
        if(node.left) stack.push(node.left);
        if(node.right) stack.push(node.right);
    }
    return arr.slice(k-1, k);
};

shaders 解析

着色器对象:着色器对象管理一个顶点着色器或一个片元着色器,每一个着色器都有一个着色器对象

程序对象:程序对象是管理着色器对象的容器。WebGL 中,一个程序对象必须包含一个顶点着色器和一个片元着色器

运行过程

  1. 创建着色器对象
  2. 向着色器对象中填充着色器程序的源代码
  3. 编译着色器
  4. 创建程序对象
  5. 为程序对象分配着色器
  6. 连接程序对象
  7. 使用程序对象

创建着色器对象

通过 gl.createShader() 函数创建着色器,type:gl.VERTEX_SHADER(顶点着色器) 和 gl.FRAGMENT_SHADER(片元着色器)

创建着色器对象之后可以通过 gl.deleteShader 对着色器对象进行删除,

制定着色器对象的代码

通过 gl.shaderSource() 函数向着色器指定 GLSL ES 源码

编译着色器

当调用 gl.compileShader() 函数时,会对着色器源码进行编译,编译完成之后可以通过 gl.getShaderParameter() 获取当前着色器编译的情况,通过 SHADER_TYPE、DELETE_STATUS、COMPILE_STATUS 获取当前着色器的类型、删除状态、编译成功与否。

如果编译失败着色器会写入信息日志,通过 gl.getShaderInfoLog() 来获取

创建程序对象

通过 gl.createProgram() 来创建程序对象。也可以通过 gl.deleteProgram(),创建了程序对象之后需要附上两个着色器

我们往着色器中传入参数的时候就是通过程序对象进行传入的。

为程序对象分配着色器对象

通过 gl.attachShader() 为程序对象分配着色器对象,WebGL 系统要运行起来必须要两个着色器,一个顶点着色器,一个片元着色器。

被分配的着色器对象不一定要是编译代码,也可以分配一个空的着色器对象。也可以通过 gl.detachShader() 进行解绑

连接程序对象

为程序对象分配着色器对象之后,还需要通过 gl.linkProgram() 对两个着色器进行链接起来,目的是保证:

  1. 顶点着色器和片元着色器的 varying 变量同名同类型,且一一对应;
  2. 顶点着色器对每个 varying 变量赋了值;
  3. 顶点着色器和片元着色器中的同名 uniform 变量也是同类型的。
  4. 着色器中的 attrbuite 变量、nuiform 变量和 varying 变量的个数没有超过着色器的上线

告知系统所使用的程序对象

通过调用 gl.useProgram() 告知 webgl 系统绘制时使用哪个程序对象

程序解析

const ininShaders = (gl, vshader, fshader) => {
    var program = createProgram(gl, vshader, fshader);
    ...
    // 告知使用的程序对象
    gl.useProgram(program)
    gl.program = program
    return true
}

const createProgram =  (gl, vshader, fshader) => {
    // 创建着色器对象
    var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
    var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
    ...
    // 创建程序对象
    var program = gl.createProgram();
    ...
    // 为程序对象分配着色器
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    
    // 连接着色器
    gl.linkProgram(program);
    
    // 检查连接
    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
    
    ...
    return program;
}

const loadShader = (gl, type, source) => {
    // 创建着色器对象
    var shader = gl.createShader(type);
    
    ...
    // 设置着色器的源代码
    gl.shaderSource(shader, source);
    
    // 编译着色器
    gl.compileShader(shader);
    
    // 检查着色器的编译状态
    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    
    ...
    return shader
}