WebGL

博客分类: 江河计划

WebGL

算法

递增的三元子序列

给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。

数学表达式如下:

如果存在这样的 i, j, k,  且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。
var increasingTriplet = function(nums) {
    if(nums.length < 3) return false;
    var first = Number.MAX_SAFE_INTEGER;
    var second = Number.MAX_SAFE_INTEGER;
    for(let i=0; i<nums.length; i++){
        if (nums[i] > second) {
            return true
        } else if (nums[i] < first) {
            first = nums[i];
        } else if(nums[i] > first && nums[i] < second){
            second = nums[i]
        }
    }
    return false;
};

纹理

向模型上贴的图片我们称之为纹理,将纹理贴到模型的过程我们成为纹理映射。

纹理映射

  1. 准备好映射到集合图形上的纹理图像
  2. 为几何图形配置纹理映射方式
  3. 加载纹理图像,对其进行一些配置,以在 WebGL 中使用它
  4. 在片元着色器中将相应的纹素从纹理中抽取出来,并将纹素的颜色赋给片元

纹理坐标

纹理坐标是纹理图像上的坐标,通过纹理坐标可以在纹理图像上获取纹素颜色。WebGL 中的纹理坐标系统是二维的。为了和常见的二维坐标系分开,使用 s 和 t 作为坐标轴

initVertexBuffers(gl){
    var verticesTexCoords = new Float32Array(
        [
    //     -0.5, 0.5, 0.0, 1.0,
    //     -0.5, -0.5, 0.0, 0.0,
    //     0.5, 0.5, 1.0, 1.0,
    //     0.5, -0.5, 1.0, 0.0,
            -0.5, 0.5, -0.3, 1.7,
            -0.5, -0.5, -0.3, -0.2,
            0.5, 0.5, 1.7, 1.7,
            0.5, -0.5, 1.7, -0.2
        ]
    );
    var n=4;//顶点数目

    //创建缓冲区对象
    var vertexTexCoordBuffer = gl.createBuffer();
    if(!vertexTexCoordBuffer){
        console.log("Failed to create thie buffer object");
        return -1;
    }

    //将缓冲区对象保存到目标上
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);

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

    var FSIZE = verticesTexCoords.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, 2, gl.FLOAT, false, FSIZE*4, 0);
    //连接a_Postion变量与分配给它的缓冲区对象
    gl.enableVertexAttribArray(a_Position);

    //将纹理坐标分配给a_TexCoord并开启它
    var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
    if(a_TexCoord < 0){
        console.log("Failed to get the storage location of a_TexCoord");
        return -1;
    }

    gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE*4, FSIZE*2);
    gl.enableVertexAttribArray(a_TexCoord);

    return n;
},
initTextures(gl, n){
    var texture = gl.createTexture(); //创建纹理对象
    if(!texture){
        console.log('Failed to create the texture object');
        return false;
    }

    //获取u_Sampler的存储位置
    var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
    if (!u_Sampler) {
        console.log('Failed to get the storage location of u_Sampler');
        return false;
    }

    var image = new Image();//创建一个image对象
    if (!image) {
        console.log('Failed to create the image object');
        return false;
    }

    //注册图像加载时间的响应函数
    image.onload = function () {
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);//对纹理图像进行y轴反转
        //开启0号纹理单元
        gl.activeTexture(gl.TEXTURE0);
        //向target绑定纹理对象
        gl.bindTexture(gl.TEXTURE_2D, texture);

        //配置纹理参数
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
        //配置纹理图像
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);

        //将0号纹理传递给着色器
        gl.uniform1i(u_Sampler, 0);

        gl.clear(gl.COLOR_BUFFER_BIT);

        gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);//绘制矩形
    };

    //浏览器开始加载图像
    image.src = img

    return true;
}
var VSHADER_SOURCE = `
    attribute vec4 a_Position;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;
    void main() {
        gl_Position =  a_Position;
        v_TexCoord = a_TexCoord;
    }
`;
var FSHADER_SOURCE = `
    #ifdef GL_ES
    precision mediump float;
    #endif
    uniform sampler2D u_Sampler;
    varying vec2 v_TexCoord;
    void main() {
        gl_FragColor = texture2D(u_Sampler, v_TexCoord);
    }
`;
var gl = canvas.getContext('webgl');
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
this.gl = gl;
var n = this.initVertexBuffers(gl)
gl.clearColor(0.0, 0.0, 0.0, 1.0);
this.initTextures(gl, n);
  1. 顶点着色器中接收顶点的纹理坐标,光栅化后传递给片元着色器
  2. 片元着色器根据片元的纹理坐标,从纹理图像中抽取出纹素颜色,赋给当前片元。
  3. 设置顶点的纹理坐标
  4. 准备待加载的纹理图像,令浏览器读取它
  5. 监听纹理图像的加载事件,一旦加载完成,就在 WebGL 系统中使用纹理

使用纹理之前需要先创建纹理,gl.createTexture(),通过gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);对纹理进行 Y 轴转换,因为纹理坐标系和 webGL 坐标系 Y 轴是相反的,通过gl.activeTexture(gl.TEXTURE0);激活纹理单元(纹理单元一般有 8 个,一般都是通过对 8 个纹理单元进行处理),绑定纹理对象gl.bindTexture(gl.TEXTURE_2D, texture);,纹理对象不能单独处理,只能通过将纹理对象绑定到缓冲区对象上才能处理

纹理参数处理,纹理参数包括TEXTURE_MIN_FILTER(纹理放大)、TEXTURE_MAG_FILTER(纹理缩小)、TEXTURE_WRAP_S(纹理水平填充)、TEXTURE_WRAP_T(纹理垂直填充)

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);