【WebGL】VAO和VBO理解

VBO

在这里插入图片描述
VBO(Vertex Buffer Object,顶点缓冲对象)是在运行图形应用程序的系统内存(通常由 CPU 管理)中创建的,但最终会被上传到图形处理单元(GPU)的内存中进行存储和使用。即CPU管理创建在内存中,之后通过如OpenGL将其上传到GPU的显存中存储

vertexAttribPointer 和 enableVertexAttribArray含义

vertexAttribPointer

语法
void gl.vertexAttribPointer(index, size, type, normalized, stride, offset);
其主要作用是告诉 WebGL 如何从缓冲区中获取顶点数据,并将其与顶点着色器中的特定属性关联起来

index指定要修改的顶点属性的索引
size指定每个顶点属性的组成数量,必须是1,2,3或4。
type指定数组中每个元素的数据类型
normalized当转换为浮点数时是否应该将整数数值归一化到特定的范围
stride一个GLsizei,以字节为单位指定连续顶点属性开始之间的偏移量(即数组中一行长度)。不能大于255。如果stride为0,则假定该属性是紧密打包的,即不交错属性,每个属性在一个单独的块中,下一个顶点的属性紧跟当前顶点之后。注意一个字节是8位,如Int16就是一个元素占两个字节,一般一个vbo只传一种类型如position,所以一般都是0
offsetGLintptr (en-US)指定顶点属性数组中第一部分的字节偏移量。必须是类型的字节长度的倍数 一般一个vbo只传一种类型如position,所以一般都是0
enableVertexAttribArray

执行gl.enableVertexArray(location)后,顶点着色器才能访问到缓冲区的数据,函数实际上处理的对象是缓冲区。

只使用VBO渲染案例(参考可以看下)

VBO使用流程
1.创建

1.创建VBO[createBuffer],
绑定VBO[bindBuffer],
上传VBO数据[bindData],
gl.enableVertexAttribArray
2.创建EBO[createBuffer],
绑定EBO[bindBuffer],
上传数据[bindData]

2.渲染的时候使用

1.绑定VBO[bindBuffer]
2.gl.vertexAttribPointer
3.绑定EBO[bindBuffer]
4.draw

<!doctype html>
<html>

<head>
	<meta charset="utf-8" />
	<title>Basic Draw Rectangle</title>
	<script id="shader-vs" type="x-shader/x-vertex">
		// precision lowp float;
 attribute vec3 position;
 attribute vec3 color;
 uniform mat4 uMVMatrix;
 uniform mat4 uPMatrix;
 varying vec4 vcolor;
 void main(void){
	 vcolor = vec4(color,1.0);
	 gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);
 }
 </script>
	<script id="shader-fs" type="x-shader/x-fragment">
		 precision lowp float;
		 varying vec4 vcolor;
 void main(void) {
	 gl_FragColor = vcolor;
 }
 </script>
</head>

<body>
	<canvas id="canvas" width="400" height="400"></canvas>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/3.4.2/gl-matrix-min.js"></script>
	<script>
		var gl;
        var mat4 = glMatrix.mat4;
		var canvas = document.getElementById('canvas');
		var pMatrix = mat4.create();
		var mvMatrix = mat4.create();
		var glProgram = null;
		var ext = null;

		function getGLContext() {
			var glContextNames = ['webgl', 'experimental-webgl'];
			for (var i = 0; i < glContextNames.length; i++) {
				try {
					gl = canvas.getContext(glContextNames[i]);
				} catch (e) { }
				if (gl) {
					gl.clearColor(74 / 255, 115 / 255, 94 / 255, 1.0);
					gl.clear(gl.COLOR_BUFFER_BIT);
					gl.viewport(0, 0, canvas.width, canvas.height);

					// ext = gl.getExtension("OES_vertex_array_object");
					break;
				}
			}
		}

		function initShaders() {
			//get shader source
			var vs_source = document.getElementById('shader-vs').innerHTML,
				fs_source = document.getElementById('shader-fs').innerHTML;

			//compile shaders
			vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
			fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);

			//create program
			glProgram = gl.createProgram();

			//attach and link shaders to the program
			gl.attachShader(glProgram, vertexShader);
			gl.attachShader(glProgram, fragmentShader);
			gl.linkProgram(glProgram);

			if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
				alert("Unable to initialize the shader program.");
			}

			//use program
			gl.useProgram(glProgram);
		}

		function makeShader(src, type) {
			//compile the vertex shader
			var shader = gl.createShader(type);
			gl.shaderSource(shader, src);
			gl.compileShader(shader);

			if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
				console.error("Error compiling shader: " + gl.getShaderInfoLog(shader));
			}
			return shader;
		}

		function toRadian(angle) {
			return angle * Math.PI / 180;
		}

		function getAllUniforms() {
			glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, 'uPMatrix');
			glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, 'uMVMatrix');
		}

		function setAllUniforms() {
			gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
			gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
		}

		function updateProjectionMatrix() {
			var near = 10;
			var far = 400;
			var widthHeightRatio = canvas.width / canvas.height;
			var fovy = 40;

			// mat4.ortho(pMatrix, -canvas.width / 2, canvas.width / 2, canvas.height / 2, -canvas.height / 2, near, far);
			mat4.perspective(pMatrix, toRadian(fovy), widthHeightRatio, near, far);
		}
		var rotate = 0;
		function updateModelViewMatrix() {
			mat4.identity(mvMatrix, mvMatrix);
			mat4.translate(mvMatrix, mvMatrix, [0, 0, -200]);
			mat4.rotate(mvMatrix, mvMatrix, toRadian(rotate++), [0, 1, 0]);
		}


		var position_buffer_mesh1 = null;
		var color_buffer_mesh1 = null;
		var index_buffer_mesh1 = null;

		function setupBuffer1() {


			// 1.创建VBO,并bind顶点属性数据
			var position = [
				-50, -30, 0,
				-5, -30, 0,
				-5, 30, 0,
				-50, 30, 0
			];
			var color = [
				1, 0, 0,
				0, 1, 0,
				0, 0, 1,
				1, 0, 0
			];
			       			
			position_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh1);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

			color_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh1);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);

			// 2.复创建EBO
			var index = [
				0, 1, 2,
				0, 2, 3
			];
			index_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh1);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index), gl.STATIC_DRAW);


			// 3.开启顶点属性
			let aVertexPosition = gl.getAttribLocation(glProgram, 'position');
			let aVertexColor = gl.getAttribLocation(glProgram, 'color');

			gl.enableVertexAttribArray(aVertexPosition);
			gl.enableVertexAttribArray(aVertexColor);








		}

		var position_buffer_mesh2 = null;
		var color_buffer_mesh2 = null;
		var index_buffer_mesh2 = null;

		function setupBuffer2() {


            // 1.创建VBO,并bind顶点属性数据
			var position = [
				5, -30, 0,
				50, -30, 0,
				50, 30, 0,
				5, 30, 0
			];
			var color = [
				1, 0, 0,
				0, 1, 0,
				0, 0, 1,
				1, 0, 0
			];

			position_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh2);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

			color_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh2);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);

			// 2.复创建EBO
			var index = [
				0, 1, 2,
				0, 2, 3
			];
			index_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh2);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index), gl.STATIC_DRAW);


			// 3.开启顶点属性
			let aVertexPosition = gl.getAttribLocation(glProgram, 'position');
			let aVertexColor = gl.getAttribLocation(glProgram, 'color');

			gl.enableVertexAttribArray(aVertexPosition);
			gl.enableVertexAttribArray(aVertexColor);









		}

		function draw(n) {
			gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
		}

		function animate() {
			requestAnimationFrame(animate);

			// update uniform
			updateModelViewMatrix();
			setAllUniforms();
			// 这个案例只使用了一个material
			let aVertexPosition = gl.getAttribLocation(glProgram, 'position');
			let aVertexColor = gl.getAttribLocation(glProgram, 'color');


			gl.clear(gl.COLOR_BUFFER_BIT);
			// draw first one
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh1);
			gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh1);
			gl.vertexAttribPointer(aVertexColor, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh1);
			draw(6);

			// draw second one
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh2);
			gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh2);
			gl.vertexAttribPointer(aVertexColor, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh2);
			draw(6);
		}











		window.onload = function () {
			getGLContext();
			initShaders();
			getAllUniforms();
			updateProjectionMatrix();
			setupBuffer1();
			setupBuffer2();

			animate();
		}
	</script>
</body>

</html>



使用VAO渲染案例(参考可以看下)

VAO使用流程
1.创建

1.创建VBO[createBuffer],绑定VBO[bindBuffer],上传VBO数据[bindData]
2.创建EBO[createBuffer],绑定EBO[bindBuffer],上传数据[bindData]
3.创建VAO[createVertexArrayOES],
绑定VAO[bindVertexArrayOES],
enableVertexAttribArray,
绑定VBO[bindBuffer],
vertexAttribPointer,
绑定EBO[bindBuffer],
取消绑定VAO[bindVertexArrayOES(null)]

2.渲染的时候使用

1.bindVertexArrayOES(vao)
2.draw

这里注意VAO使用的时候需要绑定VBO,而且EBO,VBO/EBO可以之前就创建绑定上传数据,使用VAO的时候再绑定他们就可以

代码
<!doctype html>
<html>

<head>
	<meta charset="utf-8" />
	<title>Basic Draw Rectangle</title>
	<script id="shader-vs" type="x-shader/x-vertex">
		// precision lowp float;
 attribute vec3 position;
 attribute vec3 color;
 uniform mat4 uMVMatrix;
 uniform mat4 uPMatrix;
 varying vec4 vcolor;
 void main(void){
	 vcolor = vec4(color,1.0);
	 gl_Position = uPMatrix * uMVMatrix * vec4(position, 1.0);
 }
 </script>
	<script id="shader-fs" type="x-shader/x-fragment">
		 precision lowp float;
		 varying vec4 vcolor;
 void main(void) {
	 gl_FragColor = vcolor;
 }
 </script>
</head>

<body>
	<canvas id="canvas" width="400" height="400"></canvas>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/3.4.2/gl-matrix-min.js"></script>
	<script>
		var gl;
        var mat4 = glMatrix.mat4;
		var canvas = document.getElementById('canvas');
		var pMatrix = mat4.create();
		var mvMatrix = mat4.create();
		var glProgram = null;
		var ext = null;

		function getGLContext() {
			var glContextNames = ['webgl', 'experimental-webgl'];
			for (var i = 0; i < glContextNames.length; i++) {
				try {
					gl = canvas.getContext(glContextNames[i]);
				} catch (e) { }
				if (gl) {
					gl.clearColor(74 / 255, 115 / 255, 94 / 255, 1.0);
					gl.clear(gl.COLOR_BUFFER_BIT);
					gl.viewport(0, 0, canvas.width, canvas.height);

					ext = gl.getExtension("OES_vertex_array_object");
					break;
				}
			}
		}

		function initShaders() {
			//get shader source
			var vs_source = document.getElementById('shader-vs').innerHTML,
				fs_source = document.getElementById('shader-fs').innerHTML;

			//compile shaders
			vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
			fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);

			//create program
			glProgram = gl.createProgram();

			//attach and link shaders to the program
			gl.attachShader(glProgram, vertexShader);
			gl.attachShader(glProgram, fragmentShader);
			gl.linkProgram(glProgram);

			if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
				alert("Unable to initialize the shader program.");
			}

			//use program
			gl.useProgram(glProgram);
		}

		function makeShader(src, type) {
			//compile the vertex shader
			var shader = gl.createShader(type);
			gl.shaderSource(shader, src);
			gl.compileShader(shader);

			if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
				console.error("Error compiling shader: " + gl.getShaderInfoLog(shader));
			}
			return shader;
		}

		function toRadian(angle) {
			return angle * Math.PI / 180;
		}

		function getAllUniforms() {
			glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, 'uPMatrix');
			glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, 'uMVMatrix');
		}

		function setAllUniforms() {
			gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, pMatrix);
			gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, mvMatrix);
		}

		function updateProjectionMatrix() {
			var near = 10;
			var far = 400;
			var widthHeightRatio = canvas.width / canvas.height;
			var fovy = 40;

			// mat4.ortho(pMatrix, -canvas.width / 2, canvas.width / 2, canvas.height / 2, -canvas.height / 2, near, far);
			mat4.perspective(pMatrix, toRadian(fovy), widthHeightRatio, near, far);
		}
		var rotate = 0;
		function updateModelViewMatrix() {
			mat4.identity(mvMatrix, mvMatrix);
			mat4.translate(mvMatrix, mvMatrix, [0, 0, -200]);
			mat4.rotate(mvMatrix, mvMatrix, toRadian(rotate++), [0, 1, 0]);
		}


		var position_buffer_mesh1 = null;
		var color_buffer_mesh1 = null;
		var index_buffer_mesh1 = null;
		var vao1 = null;
		function setupBuffer1() {


			// 1.创建VBO,并bind顶点属性数据
			var position = [
				-50, -30, 0,
				-5, -30, 0,
				-5, 30, 0,
				-50, 30, 0
			];
			var color = [
				1, 0, 0,
				0, 1, 0,
				0, 0, 1,
				1, 0, 0
			];
			       			
			position_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh1);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

			color_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh1);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);

			// 2.复创建EBO
			var index = [
				0, 1, 2,
				0, 2, 3
			];
			index_buffer_mesh1 = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh1);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index), gl.STATIC_DRAW);


			// 3.开启顶点属性 并 创建和绑定VAO对象
			vao1 = ext.createVertexArrayOES();
			ext.bindVertexArrayOES(vao1);
			let aVertexPosition = gl.getAttribLocation(glProgram, 'position');
			let aVertexColor = gl.getAttribLocation(glProgram, 'color');

			gl.enableVertexAttribArray(aVertexPosition);
			gl.enableVertexAttribArray(aVertexColor);

			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh1);
			gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh1);
			gl.vertexAttribPointer(aVertexColor, 3, gl.FLOAT, false, 0, 0);

			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh1);
			ext.bindVertexArrayOES(null);
		}

		var position_buffer_mesh2 = null;
		var color_buffer_mesh2 = null;
		var index_buffer_mesh2 = null;
		var vao2 = null;
		function setupBuffer2() {


            // 1.创建VBO,并bind顶点属性数据
			var position = [
				5, -30, 0,
				50, -30, 0,
				50, 30, 0,
				5, 30, 0
			];
			var color = [
				1, 0, 0,
				0, 1, 0,
				0, 0, 1,
				1, 0, 0
			];

			position_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh2);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);

			color_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh2);
			gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);

			// 2.复创建EBO
			var index = [
				0, 1, 2,
				0, 2, 3
			];
			index_buffer_mesh2 = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh2);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(index), gl.STATIC_DRAW);


			// 3.开启顶点属性 并 创建和绑定VAO对象
			vao2 = ext.createVertexArrayOES();
			ext.bindVertexArrayOES(vao2);
			let aVertexPosition = gl.getAttribLocation(glProgram, 'position');
			let aVertexColor = gl.getAttribLocation(glProgram, 'color');

			gl.enableVertexAttribArray(aVertexPosition);
			gl.enableVertexAttribArray(aVertexColor);

			gl.bindBuffer(gl.ARRAY_BUFFER, position_buffer_mesh2);
			gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
			gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer_mesh2);
			gl.vertexAttribPointer(aVertexColor, 3, gl.FLOAT, false, 0, 0);

			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer_mesh2);
			ext.bindVertexArrayOES(null);

		}

		function draw(n) {
			gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
		}

		function animate() {
			requestAnimationFrame(animate);

			// update uniform
			updateModelViewMatrix();
			setAllUniforms();

			gl.clear(gl.COLOR_BUFFER_BIT);
			// draw first one
			ext.bindVertexArrayOES(vao1);

			draw(6);

			// // draw second one
			ext.bindVertexArrayOES(vao2);

			draw(6);
		}











		window.onload = function () {
			getGLContext();
			initShaders();
			getAllUniforms();
			updateProjectionMatrix();
			setupBuffer1();
			setupBuffer2();

			animate();
		}
	</script>
</body>

</html>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值