我的github

今天来学习webgl一个重要功能:Instanced Drawing(实例化绘制),内容翻译自webgl学习网站webglfundamentals(由于英语水平尽量按原文翻译):https://webglfundamentals.org/webgl/lessons/webgl-instanced-drawing.html。

WebGL下个版本(WebGL2.0)有一个功能叫实例化绘制。

它的基本思想是:一次绘制多个相同对象的效率要高于多次绘制同一个对象。这个功能在WebGL1.0标准可以通过扩展实现,目前大部分浏览器都支持这个功能。

首先我们来做一个示例:绘制同一个对象的多个实例。

         <!-- vertex shader -->
         <scriptid="3d-vertex-shader"type="x-shader/x-vertex">
         attribute vec4 a_position;
         uniform mat4 matrix;
         void main(){
           // Multiply the position by the matrix.
           gl_Position= matrix* a_position;
         }
         </script>

        <!-- fragment shader -->
        <scriptid="3d-fragment-shader"type="x-shader/x-fragment">
        precision mediump float;        
        uniform vec4 color;
        void main(){
         gl_FragColor= color;
       }
        </script>

顶点着色器代码中实现每个顶点都乘以一个变换矩阵实现坐标转换,片元着色器中通过uniform变量传进一个颜色实现每个片元都是一样颜色。最终绘制需要编译和连接shader代码,关联attribute和uniform变量位置:

    const program= webglUtils.createProgramFromScripts(gl,['3d-vertex-shader','3d-fragment-shader']);
    const positionLoc= gl.getAttribLocation(program,'a_position');
    const colorLoc= gl.getUniformLocation(program,'color');
    const matrixLoc = gl.getUniformLocation(program,'matrix');

通过buffer关联所需顶点数据:

        const positionBuffer= gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER,newFloat32Array([
            -0.1, 0.4,
            -0.1,-0.4,
             0.1,-0.4,
             0.1,-0.4,
            -0.1, 0.4,
             0.1, 0.4,
             0.4,-0.1,
            -0.4,-0.1,
            -0.4, 0.1,
            -0.4, 0.1,
             0.4,-0.1,
             0.4, 0.1,
          ]), gl.STATIC_DRAW);
        const numVertices=12;

我们绘制5个相同(这里的相同指每个示例的形状大小一样)实例,那么就需要对应5个矩阵和5个颜色值:

      const numInstances=5;
      const matrices=[
           m4.identity(),
           m4.identity(),
           m4.identity(),
           m4.identity(),
           m4.identity(),
      ];       
      const colors =[
           [1,0,0,1,],  // red
           [0,1,0,1,],  // green
           [0,0,1,1,],  // blue
           [1,0,1,1,],  // magenta
           [0,1,1,1,],  // cyan
      ];

渲染对象首先设置attribute对应的值,循环5次(这里绘制5个实例),每次设置不同的变换矩阵和颜色。

         function render(time){
           time *=0.001;// seconds        
           gl.useProgram(program);      
           // setup the position attribute
           gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
           gl.enableVertexAttribArray(positionLoc);
           gl.vertexAttribPointer(
               positionLoc,  // location
               2,            // size (num values to pull from buffer per iteration)
               gl.FLOAT,     // type of data in buffer
               false,        // normalize
               0,            // stride (0 = compute from size and type above)
               0,            // offset in buffer
           );
           matrices.forEach((mat, ndx)=>{
             m4.translation(-0.5+ ndx *0.25,0,0, mat);
             m4.zRotate(mat, time *(0.1+0.1* ndx), mat);
             const color = colors[ndx];         
             gl.uniform4fv(colorLoc, color);
             gl.uniformMatrix4fv(matrixLoc,false, mat);
            gl.drawArrays(
                 gl.TRIANGLES,
                 0,            // offset
                 numVertices,  // num vertices per instance
             );
           });          
           requestAnimationFrame(render);
         }
         requestAnimationFrame(render);

这里我们注意到,在调用矩阵计算的数学库时,在每个方法传入已创建的矩阵对象,这样为了将计算结果保存下来以便后续使用。在大部分场景下我们不这样使用,而是直接用数学库新建一个矩阵。

这些工作完成后我们会得到5个形状大小一致、颜色和旋转角度不同的实例:

也打开以下网址可以查看效果:

http://39.106.0.97:8090/lesson/13Misc/07InstancedDrawing-01.html

参考1:https://blog.csdn.net/weixin_35970195/article/details/114879410

参考2:https://mp.weixin.qq.com/s/s2QUCAO_6FHZs3SlT0lVag

posted on 2023-04-05 17:16  XiaoNiuFeiTian  阅读(119)  评论(0编辑  收藏  举报