一.扩展介绍
OES_vertex_array_object 是一个WebGL扩展,用于引入顶点数组对象(VAO),以便更有效地组织和管理顶点属性数据和状态。
顶点数组对象(VAO)是一种用于存储和管理顶点数据和属性状态的机制,它可以将顶点属性配置和顶点缓冲绑定组合在一起。这有助于减少重复性的代码,提高性能,并使代码更易于维护。
二.简单实例-不使用扩展绘制两个四边形
- 首先创建两个四边形的顶点数据缓冲区
//创建第一个对象的顶点数据
function initVertexBuffer1(gl) {
//创建位置缓冲区
var positions = new Float32Array([
1, 0, 0,
0, 1, -1,
-1, 0, -1,
0, -1, 0,
])
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
//创建颜色缓冲区
var colors = new Float32Array([
0, 0, 1,
1, 0, 0,
0, 0, 1,
1, 0, 0,
])
var colorBuffer = gl.createBuffer();
var fSize = positions.BYTES_PER_ELEMENT
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW)
//创建索引缓冲区
const indexes=new Uint8Array([
0,1,2,
2,3,0
])
const indexBuffer=gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexes,gl.STATIC_DRAW)
return {
positionBuffer,
colorBuffer,
indexBuffer,
fSize
}
}
//创建第二个对象的顶点数据
function initVertexBuffer2(gl) {
//创建顶点缓冲区
var positions = new Float32Array([
1, 0, 0,
0, 1, 1,
-1, 0, 1,
0, -1, 0,
])
//创建缓冲区
var positionBuffer = gl.createBuffer();
var fSize = positions.BYTES_PER_ELEMENT
//将缓冲区绑定到顶点缓冲区
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
//向缓冲区写入数据,静态:不怎么变
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
//创建颜色缓冲区
var colors = new Float32Array([
1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1,
])
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW)
//创建索引缓冲区
const indexes=new Uint8Array([
0,1,2,
2,3,0
])
const indexBuffer=gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexes,gl.STATIC_DRAW)
return {
positionBuffer,
colorBuffer,
indexBuffer,
fSize
}
}
2.绘制时再次绑定切换缓冲区
const objBuffer=initVertexBuffer1(gl)
const objBuffer1=initVertexBuffer2(gl)
//绑定一个对象的顶点和索引缓冲区
function bindObjBuffer(gl,objBuffer){
const fSize=objBuffer.fSize
gl.bindBuffer(gl.ARRAY_BUFFER,objBuffer.positionBuffer)
var a_position = gl.getAttribLocation(gl.program, 'a_position');
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, fSize * 3, 0)
gl.enableVertexAttribArray(a_position)
gl.bindBuffer(gl.ARRAY_BUFFER,objBuffer.colorBuffer)
var a_color = gl.getAttribLocation(gl.program, 'a_color');
gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, fSize *3, 0)
gl.enableVertexAttribArray(a_color)
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,objBuffer.indexBuffer)
}
//根据时间绘制
var tick = function () {
//变换角度
currentAngle+=0.2
gl.clear(gl.COLOR_BUFFER_BIT)
//////////////////////普通方式绘制///////////////////////////////
//绑定第一个四边形
bindObjBuffer(gl,objBuffer)
draw(gl, currentAngle, modelMatrix, u_modelMatrix)
//绑定第二个四边形
bindObjBuffer(gl,objBuffer1)
draw(gl, 0, modelMatrix, u_modelMatrix)
//////////////////////普通方式绘制///////////////////////////////
requestAnimationFrame(tick)
}
tick()
这儿对绑定缓冲区做了一个封装
bindObjBuffer(),因为都只有positionBuffer,colorBuffer和indexBuffer,但是如果不一致的话这儿就不能做封装,代码会更加复杂
三.使用扩展绘制
1.获取扩展
//获取扩展
var ext = gl.getExtension("OES_vertex_array_object");
2.创建顶点缓冲区数组
const vao =ext.createVertexArrayOES(); ext.bindVertexArrayOES(vao);
//创建第一个对象的顶点数据
function initVertexArrayObject1(gl,ext) {
//创建顶点缓冲区数组
const vao =ext.createVertexArrayOES();
ext.bindVertexArrayOES(vao);
//创建位置缓冲区
var positions = new Float32Array([
1, 0, 0,
0, 1, -1,
-1, 0, -1,
0, -1, 0,
])
var fSize = positions.BYTES_PER_ELEMENT
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
var a_position = gl.getAttribLocation(gl.program, 'a_position');
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, fSize * 3, 0)
gl.enableVertexAttribArray(a_position)
//创建颜色缓冲区
var colors = new Float32Array([
0, 0, 1,
1, 0, 0,
0, 0, 1,
1, 0, 0,
])
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW)
var a_color = gl.getAttribLocation(gl.program, 'a_color');
gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, fSize *3, 0)
gl.enableVertexAttribArray(a_color)
//创建索引缓冲区
const indexes=new Uint8Array([
0,1,2,
2,3,0
])
const indexBuffer=gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexes,gl.STATIC_DRAW)
return vao
}
//创建第一个对象的顶点数据
function initVertexArrayObject2(gl,ext) {
//创建顶点缓冲区数组
const vao =ext.createVertexArrayOES();
ext.bindVertexArrayOES(vao);
//创建位置缓冲区
var positions = new Float32Array([
1, 0, 0,
0, 1, 1,
-1, 0, 1,
0, -1, 0,
])
var fSize = positions.BYTES_PER_ELEMENT
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW)
var a_position = gl.getAttribLocation(gl.program, 'a_position');
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, fSize * 3, 0)
gl.enableVertexAttribArray(a_position)
//创建颜色缓冲区
var colors = new Float32Array([
1, 1, 1,
1, 1, 1,
1, 1, 1,
1, 1, 1,
])
var colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer)
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW)
var a_color = gl.getAttribLocation(gl.program, 'a_color');
gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, fSize *3, 0)
gl.enableVertexAttribArray(a_color)
//创建索引缓冲区
const indexes=new Uint8Array([
0,1,2,
2,3,0
])
const indexBuffer=gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer)
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexes,gl.STATIC_DRAW)
return vao
}
3.绑定绘制
const vao=initVertexArrayObject1(gl,ext)
const vao1=initVertexArrayObject2(gl,ext)
//根据时间绘制
var tick = function () {
//变换角度
currentAngle+=0.2
gl.clear(gl.COLOR_BUFFER_BIT)
//绑定第一个四边形
//bindObjBuffer(gl,objBuffer)
//draw(gl, currentAngle, modelMatrix, u_modelMatrix)
//绑定第二个四边形
//bindObjBuffer(gl,objBuffer1)
//draw(gl, 0, modelMatrix, u_modelMatrix)
///////////////////////////扩展绘制/////////////////////////////////////
ext.bindVertexArrayOES(vao);
draw(gl, currentAngle, modelMatrix, u_modelMatrix)
ext.bindVertexArrayOES(vao1);
draw(gl, 0, modelMatrix, u_modelMatrix)
///////////////////////////扩展绘制/////////////////////////////////////
requestAnimationFrame(tick)
}
tick()
通过上述代码可以看出,
vao有点类似于objBuffer,如果可以封装objBuffer绘制时绑定,代码非常类似,但是在性能上却不一样,毕竟objBuffer要重复绑定好多次,何况大多数情况下并不能封装
四.在webgl2中的情况
在webgl2 中,VAO已经作为官方标准一部分,不以扩展方式存在,具体用法如下:
1.创建绑定vao改为如下写法:
var vao = gl.createVertexArray();
gl.bindVertexArray(vao);
2.绘制时
gl.bindVertexArray(vao);
draw(gl, currentAngle, modelMatrix, u_modelMatrix)
gl.bindVertexArray(vao1);
draw(gl, 0, modelMatrix, u_modelMatrix)