今天来学习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