WebGL-学习

绘制接口

WebGLRenderingContext.drawArrays()

void gl.drawArrays(mode, first, count);

参数

  • mode

    指定绘制图元的方式,可能值如下。

    gl.POINTS: 绘制一系列点。

    gl.LINE_STRIP: 绘制一个线条。即,绘制一系列线段,上一点连接下一点。

    gl.LINE_LOOP: 绘制一个线圈。即,绘制一系列线段,上一点连接下一点,并且最后一点与第一个点相连。

    gl.LINES: 绘制一系列单独线段。每两个点作为端点,线段之间不连接。

    gl.TRIANGLE_STRIP:绘制一个三角带

    gl.TRIANGLE_FAN:绘制一个三角扇

    gl.TRIANGLES: 绘制一系列三角形。每三个点作为顶点。

  • first

    指定从哪个点开始绘制。

  • count

    指定绘制需要使用到多少个点。

创建program

WebGLRenderingContext.createProgram()

WebGLProgram gl.createProgram();

用法如下:

var program = gl.createProgram();

// 添加预先定义好的顶点着色器和片段着色器
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);

gl.linkProgram(program);

if ( !gl.getProgramParameter( program, gl.LINK_STATUS) ) {
  var info = gl.getProgramInfoLog(program);
  throw "Could not compile WebGL program. \n\n" + info;
}
  //使用program
  gl.useProgram(program);

attribute关键字

声明顶点相关数据的时候需要用到attribute关键字。

const vsSource = `
    attribute vec4 aVertexPosition;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;

    void main() {
      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
    }
  `;
    const fsSource = `
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
  `;

attribute vec4 aVertexPosition;声明的变量aVertexPosition表示矩形所有顶点的位置坐标。WebGL着色器语言之所以规定attribute这样一个关键字,目的是为了javascript可以调用相关的WebGL API把顶点相关数据从javascript传递给顶点着色器attribute声明的变量。

先将变量指定给js中的变量

const programInfo={
    program:shaderProgram,
    attribLocations:{
        vertexPosition:gl.getAttribLocation(shaderProgram,'aVertexPosition')
    },
    getUniformLocations:{
        projectionMatrix:gl.getUniformLocation(shaderProgram,'uProjectionMatrix'),
        modelViewMatrix:gl.getUniformLocation(shaderProgram,'uModelViewMatrix'),
    },
}

javascript会调用相关的WebGL API通过下面的代码把类型数组data中包含的顶点位置坐标数据传递给顶点着色器中attribute关键字声明的变量aVertexPosition

此部分代码的作用总体上是把内存中顶点数据输入显存,提高图形的处理效率。

//告诉WebGL如何将位置从位置缓冲区拉出到 vertexPosition 属性中。
  {
      const numComponents=2;  //每次迭代取两个值
      const type=gl.FLOAT;    //这个数据在buffer中是32位浮点数
      const normalize=false;
      const stride=0;         //从一组值到下一组值获取多少字节
                              //0等于使用类型和组件
      const offset=0          //从缓存器的多少字节开始
      //顶点数组data数据传入缓冲区
      gl.bindBuffer(gl.ARRAY_BUFFER,buffers.position);
      //缓冲区中的数据按照一定的规律传递给位置变量
    	gl.vertexAttribPointer(
          programInfo.attribLocations.vertexPosition,
          numComponents,
          type,
          normalize,
          stride,
          offset
      );
      gl.enableVertexAttribArray(
          programInfo.attribLocations.vertexPosition
      );

      //告诉WebGL在绘制时使用我们的程序
      gl.useProgram(programInfo.program);

      //设置shader uniforms
      gl.uniformMatrix4fv(
          programInfo.getUniformLocations.projectionMatrix,
          false,
          projectionMatrix
      );
      gl.uniformMatrix4fv(
          programInfo.getUniformLocations.modelViewMatrix,
          false,
          modelViewMatrix);

      {
          const offset = 0;
          const vertexCount = 4;
          gl.drawArrays(gl.POINTS, offset, vertexCount);
          // gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
      }
  }
drawArrays整体执行顺序

![截屏2023-02-24 13.54.02](/Users/a666/Desktop/截屏2023-02-24 13.54.02.png)

示例源码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"
            integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ=="
            crossorigin="anonymous"
            defer></script>
</head>
<body onload="main()">
<canvas id="myCanvas" width="640" height="640"></canvas>
</body>
<script>
function main(){
    let canvas=document.getElementById('myCanvas');
    let gl=canvas.getContext("webgl");
    if(!gl){
        alert("无法初始化WebGL,你的浏览器、操作系统或硬件等可能不支持WebGL")
        return;
    }
    //使用完全不透明等黑色清除所有图像
    gl.clearColor(0.0,0.0,0.0,1.0);
    // Vertex shader program
    //用上面指定等颜色清除缓冲区
    gl.clear(gl.COLOR_BUFFER_BIT);
    const vsSource = `
    attribute vec4 aVertexPosition;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;

    void main() {
      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
    }
  `;
    const fsSource = `
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
  `;
    const shaderProgram=initShaderProgram(gl,vsSource,fsSource);

    const programInfo={
        program:shaderProgram,
        attribLocations:{
            vertexPosition:gl.getAttribLocation(shaderProgram,'aVertexPosition')
        },
        getUniformLocations:{
            projectionMatrix:gl.getUniformLocation(shaderProgram,'uProjectionMatrix'),
            modelViewMatrix:gl.getUniformLocation(shaderProgram,'uModelViewMatrix'),
        },
    }

    const buffers=initBuffers(gl);

    drawScene(gl,programInfo,buffers)
}


//初始化着色器,让WebGL指导如何绘制我们的数据
function initShaderProgram(gl,vsSource,fsSource){
    const vertexShader=loadShader(gl,gl.VERTEX_SHADER,vsSource);
    const fragmentShader=loadShader(gl,gl.FRAGMENT_SHADER,fsSource);
    //创建着色器程序
    const shaderProgram=gl.createProgram();
    gl.attachShader(shaderProgram,vertexShader);
    gl.attachShader(shaderProgram,fragmentShader);
    gl.linkProgram(shaderProgram);

    //创建失败,alert
    if(!gl.getProgramParameter(shaderProgram,gl.LINK_STATUS)){
        alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
        return null;
    }
    return shaderProgram;
}

//创建指定类型的着色器,上传source源码并编译
function loadShader(gl,type,source){
    const shader=gl.createShader(type);
    //将source传送给对象
    gl.shaderSource(shader,source);
    //编译shader程序
    gl.compileShader(shader);
    //判定是否编译成功
    if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){
        alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
    return shader
}

//创建对象
function initBuffers(gl){
    //创建一个buffer为这个正方形区域
    const positionBuffer=gl.createBuffer();
    //选中这个positionBuffer作为一个应用buffer
    gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);
    //创建一个数组,关于正方形的位置
    const positions=
    //     1.0,1.0,
    //     -1.0,1.0,
    //     1.0,-1.0,
    //     -1.0,-1.0,
    // ]
    [0.5,0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5]
    //现在将此数组传到WebGL去构建形状,我们通过创建32位浮点数组,然后将其填入当前buffer中
    gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);
    return {
        position:positionBuffer,
    }
}

//绘制场景
function drawScene(gl,programInfo,buffers){
    gl.clearColor(0.0,0.0,0.0,0.8); //填充黑色,0.8透明度
    gl.clearDepth(1.0)              //清空所有
    gl.enable(gl.DEPTH_TEST)        //depth能够使用测试
    gl.depthFunc(gl.LEQUAL)         //Near things obscure far things

    //清空canvas在绘制之前
    gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);

    //创建投影矩阵,一种特殊的矩阵常被用于模拟相机失真
    //我们的视野是45度,具有高度和宽度匹配画布的显示大小并且我们只想在0.1单位之间看到物体,距离相机100单位远
    const fieldOfView=45*Math.PI/180;   //转换为极坐标
    const aspect=gl.canvas.clientWidth/gl.canvas.clientHeight;
    const zNear=0.1;
    const zFar=100.0;
    const projectionMatrix=mat4.create();

    mat4.perspective(projectionMatrix,fieldOfView,aspect,zNear,zFar);

    //设置绘制位置为识别点,位于场景中心
    const modelViewMatrix = mat4.create();

    //现在将绘图位置移动到我们想要的位置
    mat4.translate(modelViewMatrix, //目标矩阵
                    modelViewMatrix,//要翻译的矩阵
                    [-0.0,0.0,-6.0])//要移动的数据

    //告诉WebGL如何将位置从位置缓冲区拉出到 vertexPosition 属性中。
    {
        const numComponents=2;  //每次迭代取两个值
        const type=gl.FLOAT;    //这个数据在buffer中是32位浮点数
        const normalize=false;
        const stride=0;         //从一组值到下一组值获取多少字节
                                //0等于使用类型和组件
        const offset=0          //从缓存器的多少字节开始
        gl.bindBuffer(gl.ARRAY_BUFFER,buffers.position);
        gl.vertexAttribPointer(
            programInfo.attribLocations.vertexPosition,
            numComponents,
            type,
            normalize,
            stride,
            offset
        );
        gl.enableVertexAttribArray(
            programInfo.attribLocations.vertexPosition
        );

        //告诉WebGL在绘制时使用我们的程序
        gl.useProgram(programInfo.program);

        //设置shader uniforms
        gl.uniformMatrix4fv(
            programInfo.getUniformLocations.projectionMatrix,
            false,
            projectionMatrix
        );
        gl.uniformMatrix4fv(
            programInfo.getUniformLocations.modelViewMatrix,
            false,
            modelViewMatrix);

        {
            const offset = 0;
            const vertexCount = 4;
            gl.drawArrays(gl.POINTS, offset, vertexCount);
            // gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
        }
    }
}
</script>
</html>