正常情况下,每绘制一个模型都要调用一次 gl.uniform4v,gl.uniformMatrix4fv 还有gl.drawArrays。加入需要绘制n个相同的模型,那么就需要调用n次 gl.uniform4v,gl.uniformMatrix4fv 还有gl.drawArrays。如果我们的着色器很复杂的化,那么调用的WebGL方法就会很多。

实例化 就是一个帮助我们减少函数调用的好路子。 它的工作原理是让你告诉 WebGL 你想绘制多少次相同的物体(实例的数量)。

对于每个 attribute,你可以让它每次调用顶点着色器时迭代到缓冲区的 下一个值(默认行为),或者是每绘制 N(N通常为1)个实例时才迭代到 下一个值。

# 1.WebGL性能优化 - 实例化绘制 我们不妨使用 attribute来提供matrix和color的值以取代uniform 。 我们会在缓冲区里为每个实例提供矩阵和颜色,设置好从缓冲区里读取数据的 attribute,然后告诉WebGL只有在绘制下一个实例的时候才迭代到下一个值。

# 1.顶点着色器

1234567891011121314151617# 2.片元着色器 因为 attribute 只能在顶点着色器中声明所以我们需要用 varying 把颜色传递到片元着色器。

12345678# 3.启用实例化 const canvas = document.querySelector('#canvas');

const gl = canvas.getContext('webgl');

if (!gl) {

return;

}

const ext = gl.getExtension('ANGLE_instanced_arrays');

if (!ext) {

return alert('need ANGLE_instanced_arrays');

}

12345678910# 4. 创建缓冲区来存储提供给attribute的矩阵和颜色 new Float32Array(matrixData.buffer,byteOffsetToMatrix,numFloatsForView)参数的意义:

matrixData.buffer: 表示总字节大小 byteOffsetToMatrix: 表示字节偏移量 numFloatsForView:指定创建的矩阵视图包含的浮点数数量 // 为每一个实例设置矩阵

const numInstances = 5;

// make a typed array with one view per matrix

const matrixData = new Float32Array(numInstances * 16);

const matrices = [];

for (let i = 0; i < numInstances; ++i) {

const byteOffsetToMatrix = i * 16 * 4;

const numFloatsForView = 16;

// 初始化矩阵

matrices.push(new Float32Array(matrixData.buffer,byteOffsetToMatrix,numFloatsForView));

}

const matrixBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, matrixBuffer);

// 只为缓冲区申请特定大小的空间

gl.bufferData(gl.ARRAY_BUFFER, matrixData.byteLength, gl.DYNAMIC_DRAW);

// 为每一个实例设置颜色

const colors = new Float32Array([

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

]);

const colorBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);

gl.bufferData(gl.ARRAY_BUFFER,colors, gl.STATIC_DRAW);

123456789101112131415161718192021222324252627注意: gl.bufferData最后一个参数是 gl.DYNAMIC_DRAW。这是一个给WebGL的指示, 告诉它我们要经常刷新这里的数据。

# 5.绘制 更新所有的矩阵 matrices.forEach((mat, ndx) => {

m4.translation(-0.5 + ndx * 0.25, 0, 0, mat);

m4.zRotate(mat, time * (0.1 + 0.1 * ndx), mat);

});

1234上传新的矩阵数据

gl.bufferSubData(gl.ARRAY_BUFFER, 0, matrixData) 用于更新已存在的缓冲区对象中的子数据,用于将新数据(或部分数据)上传到已绑定的缓冲区对象中。因为前面调用了gl.bufferData(gl.ARRAY_BUFFER, matrixData.byteLength, gl.DYNAMIC_DRAW); gl.bindBuffer(gl.ARRAY_BUFFER, matrixBuffer);

gl.bufferSubData(gl.ARRAY_BUFFER, 0, matrixData);

12为矩阵设置attribute const bytesPerMatrix = 4 * 16;

for (let i = 0; i < 4; ++i) {

const loc = matrixLoc + i;

gl.enableVertexAttribArray(loc);

// 注意stride和offset

const offset = i * 16; // 一行有4个单精度浮点数,1个就占用4字节

gl.vertexAttribPointer(

loc, // location

4, // size (num values to pull from buffer per iteration)

gl.FLOAT, // type of data in buffer

false, // normalize

bytesPerMatrix, // stride, num bytes to advance to get to next set of values

offset, // offset in buffer

);

// 这行说的是attribute只对下一个实例才进行迭代

ext.vertexAttribDivisorANGLE(loc, 1);

}

1234567891011121314151617为颜色设置attribute // 为颜色设置attribute

gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);

gl.enableVertexAttribArray(colorLoc);

gl.vertexAttribPointer(colorLoc, 4, gl.FLOAT, false, 0, 0);

// this line says this attribute only changes for each 1 instance

ext.vertexAttribDivisorANGLE(colorLoc, 1);

123456绘制所有的模型 ext.drawArraysInstancedANGLE(

gl.TRIANGLES,

0, // offset

numVertices, // 每个实例的顶点数

numInstances, // 实例的数量

);

123456demo地址 非实例化绘制 (opens new window) demo地址 实例化绘制 (opens new window)

# 2.WebGL - 顶点索引 在 WebGL 中有两个基本的绘制函数。 gl.drawArrays 和 gl.drawElements。 这个网站的文章中,大部分是调用 gl.drawArrays 的。

gl.drawElements 需要一个填充了顶点索引的缓存,然后以此来绘制。

使用顶点索引时,有几个需要注意的地方。

缓冲区的对象不一样了 使用顶点缓冲时的缓冲类型是ELEMENT_ARRAY_BUFFER,之前是 gl.ARRAY_BUFFER。

创建顶点缓冲 // create the buffer

const indexBuffer = gl.createBuffer();

// make this buffer the current 'ELEMENT_ARRAY_BUFFER'

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);

// Fill the current element array buffer with data

const indices = [

0, 1, 2, // first triangle

2, 1, 3, // second triangle

];

gl.bufferData(

gl.ELEMENT_ARRAY_BUFFER,

new Uint16Array(indices),

gl.STATIC_DRAW

);

123456789101112131415绘制对象的方法不一样了

之前的方法 const primitiveType = gl.TRIANGLES;

const offset = 0;

const count = 6;//num vertices per instance

gl.drawArrays(primitiveType,offset,count);

1234使用顶点索引

const primitiveType = gl.TRIANGLES;

const offset = 0;

const count = 6;

const indexType = gl.UNSIGNED_SHORT;

gl.drawElements(primitiveType, count, indexType, offset);

12345demo地址 顶点索引 (opens new window)

参考文档

WebGL 顶点索引 (opens new window) WebGL性能优化 - 实例化绘制 (opens new window)

阅读量:

评 论:

top
Copyright © 2088 篮球世界杯美国队名单_意大利世界杯预选赛 - pyqtui.com All Rights Reserved.
友情链接