WebGL

博客分类: 江河计划

WebGL

算法

奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
var oddEvenList = function(head) {
    if(!head || !head.next){
        return head;
    }
    var odd = head;
    var even = head.next;
    var tmp = even;
    while(even && even.next){
        odd.next = even.next;
        odd = odd.next;
        even.next = odd.next;
        even = even.next;
    }
    odd.next = tmp
    return head
};

可视空间

可视空间分两种:正射投影和透视投影

正射投影中平行的光 照射到与其平行的物体就变成点或者线了,看不到平行物体的侧面

透视投影中平行的光实际上发散出去的(就像人眼看平行的铁轨,明明是平行的,但是透视效果确实两个平行铁轨越远越相较于某一点),实际的光是不平行的 当然就可以看到物体的侧面。

正射投影

正射投影是的可视空间由近裁剪面和远裁剪面决定。接近视点的面试近裁剪面,投影位置为远裁剪面,我们实际看到的内容就仅仅是可视空间中的内容

当我们不断调整近裁剪面和远裁剪面时,如果图形不在可视空间内之后就会看不见

var VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    uniform mat4 u_ProjMatrix;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_ProjMatrix * a_Position;
        gl_PointSize = 10.0;
        v_Color = a_Color;
    }
`;
var FSHADER_SOURCE = `
    precision mediump float;
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
`;
var gl = canvas.getContext('webgl');
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
this.gl = gl;
var n = this.initVertexBuffers(gl)
var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
//设置视点、视线、上方向
var projMatrix = new Matrix4();
 document.onkeydown = function (ev) {
    keydown(ev, gl, n, u_ProjMatrix,projMatrix);
};
draw(gl, n, u_ProjMatrix, projMatrix);

var g_near = 0.0, g_far = 0.5;
function keydown(ev, gl, n, u_ProjMatrix, projMatrix) {
    switch (ev.keyCode){
        case 39: g_near += 0.01; break; //right
        case 37: g_near -= 0.01; break; //left
        case 38: g_far += 0.01; break; //up
        case 40: g_far -=0.01; break; //down
        default: return;
    }
    draw(gl, n, u_ProjMatrix, projMatrix);
}

function draw(gl, n, u_ProjMatrix, projMatrix) {
    projMatrix.setOrtho(-1, 1, -1, 1, g_near, g_far);

    //将视图矩阵传递给u_ViewMatrix变量
    gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);

    gl.clear(gl.COlOR_BUFFER_BIT);

    console.log('near: ' + Math.round(g_near * 100)/100 + ', far: ' + Math.round(g_far * 100)/100)

    gl.drawArrays(gl.TRIANGLES, 0, n);
}

透视投影

平行的视角看过去,物体没有那么真实,我们真实看到的世界一定是远小近大的,而不是平行的。透视投影也会有可视空间,同样的处于可视空间内的物体才会被显示出来。

但是透视投影近裁剪面比远裁剪面小,链接视点、近裁剪面、远裁剪面就会形成一个夹角,所以我们在定义透视投影时,一般使用,视角的夹角、近裁剪面的宽高比,视角距离近裁剪面和远裁剪面的距离

三个一样大小的三角形,从视角上看远近不同,大小也就不同,所以透视投影更贴近我们的视觉直观感受

var VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec4 a_Color;
    uniform mat4 u_ViewMatrix;
    uniform mat4 u_ProjMatrix;
    varying vec4 v_Color;
    void main() {
        gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;
        gl_PointSize = 10.0;
        v_Color = a_Color;
    }
`;
var FSHADER_SOURCE = `
    precision mediump float;
    varying vec4 v_Color;
    void main() {
        gl_FragColor = v_Color;
    }
`;
var gl = canvas.getContext('webgl');
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
this.gl = gl;
var n = this.initVertexBuffers(gl)

var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');

//设置视点、视线、上方向
var viewMatrix = new Matrix4();
viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
var projMatrix = new Matrix4();
projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);

gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);

gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, n);

initVertexBuffers(gl){
    var verticesColors = new Float32Array(
        [
            // Three triangles on the right side
            0.75,  1.0,  -4.0,  0.4,  1.0,  0.4, // The back green one
            0.25, -1.0,  -4.0,  0.4,  1.0,  0.4,
            1.25, -1.0,  -4.0,  1.0,  0.4,  0.4,

            0.75,  1.0,  -2.0,  1.0,  1.0,  0.4, // The middle yellow one
            0.25, -1.0,  -2.0,  1.0,  1.0,  0.4,
            1.25, -1.0,  -2.0,  1.0,  0.4,  0.4,

            0.75,  1.0,   0.0,  0.4,  0.4,  1.0,  // The front blue one
            0.25, -1.0,   0.0,  0.4,  0.4,  1.0,
            1.25, -1.0,   0.0,  1.0,  0.4,  0.4,

            // Three triangles on the left side
            -0.75,  1.0,  -4.0,  0.4,  1.0,  0.4, // The back green one
            -1.25, -1.0,  -4.0,  0.4,  1.0,  0.4,
            -0.25, -1.0,  -4.0,  1.0,  0.4,  0.4,

            -0.75,  1.0,  -2.0,  1.0,  1.0,  0.4, // The middle yellow one
            -1.25, -1.0,  -2.0,  1.0,  1.0,  0.4,
            -0.25, -1.0,  -2.0,  1.0,  0.4,  0.4,

            -0.75,  1.0,   0.0,  0.4,  0.4,  1.0,  // The front blue one
            -1.25, -1.0,   0.0,  0.4,  0.4,  1.0,
            -0.25, -1.0,   0.0,  1.0,  0.4,  0.4,
        ]);
    var n = 18; //点的个数


    //创建缓冲区对象
    var verteColorBuffer = gl.createBuffer();
    if (!verteColorBuffer) {
        console.log("Failed to create thie buffer object");
        return -1;
    }
    //将缓冲区对象保存到目标上
    gl.bindBuffer(gl.ARRAY_BUFFER, verteColorBuffer);

    //向缓存对象写入数据
    gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);

    var FSIZE = verticesColors.BYTES_PER_ELEMENT;

    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 -1;
    }
    //将缓冲区对象分配给a_Postion变量
    gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE *6, 0);
    //连接a_Postion变量与分配给它的缓冲区对象
    gl.enableVertexAttribArray(a_Position);

    var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
    if (a_Color < 0) {
        console.log("Failed to get the storage location of a_Position");
        return -1;
    }

    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
    gl.enableVertexAttribArray(a_Color);

    gl.bindBuffer(gl.ARRAY_BUFFER, null);//取消绑定的缓冲区对象
    return n;
}

层级关系

正常情况下 webgl 会根据先设置的图形挡住后面的图形,这是为了提高渲染效率,所以不会是离我们视点近的物体遮挡距离远的物体。

webgl 提供了隐藏面消除来解决这个问题。开启隐藏面消除,消除之后就会按照位置放置遮挡位置而不是先后顺序

gl.enable(gl.DEPTH_TEST)
gl.clear(gl.COLOR_BUFFER_BIT);