WebGL学习笔记03
前一篇文章的实验代码只是绘制一个红点,实验代码中我们并没有告诉WebGL要绘制哪些顶点,顶点要以何种方式绘制。
接下来要介绍的知识点就是用来告诉WebGL要绘制哪些顶点,以及要如何绘制的:
- Buffer
- Attribute
- drawArrays()
首先我们需要有一组顶点数据,WebGL使用Buffer对象来存储顶点数据,因为WebGL渲染的时候用的是数据来源是显存,而我们的程序运行在内存,所以这边需要有一个把数据从内存提交到显存的过程,调用者需要告诉WebGL数据在哪里,当WebGL开始渲染的时候会将内存数据拷贝到显存中。
所以除了创建Buffer对象之外,我们还需要在程序中维护一份等待渲染的顶点集合,在JS中用Float32Array类型来表示,代码大概像这样:
var vertices = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5
]);
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return;
}
// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
通过bindBuffer(),我们告诉WebGL接下来要渲染的顶点数据来源是vertexBuffer这个集合,通过bufferData(),我们将内存里的待渲染顶点集合和显存中的顶点来源关联起来。
在做完这些事情之后,我们还需要告诉Vertex Shader应该如何使用这些顶点,所以这里需要用到Attribute,Attribute是Shader中的一种变量类型,调用者可以通过getAttribLocation()和vertexAttribPointer()来设置VShader的Attribute参数。
以下是加入Attribute参数的VShader:
attribute vec4 a_Position;
void main() {
gl_Position = a_Position; // Set the vertex coordinates of the point
}
之前设置gl_Position这个内置变量的语句变成了将a_Position赋值给gl_Position。
程序中则通过以下过程设置VertexBuffer的使用:
var a_Position = gl.getAttribLocation(program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}
// Assign the buffer object to a_Position variable
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
其中vertexAttribPointer()的第二个参数2,用来告诉Shader,VertexBuffer中的数据是每两个一组,组成一个a_Position。因为我们要绘制的是一个二维平面的三角形,所以只需要知道每个顶点的X轴和Y轴坐标就可以了。
接着就是调用drawArrays()来进行渲染,drawArrays()的第一个参数用来告诉WebGL要如何绘制这些顶点,是要绘制成三角形还是扇面等。
完成的实验代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebGL Labs 02 - Triangle</title>
<script src="GLUtil.js"></script>
<script type="text/javascript">
// Vertex shader program
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
'}\n';
// Fragment shader program
var FSHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // Set the point color
'}\n';
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = GLUtil.GetContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Create shader program.
var program = GLUtil.CreateProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE);
if (!program) {
console.log('Failed to create program for WebGL');
return;
}
gl.useProgram(program);
var vertices = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5
]);
// Create a buffer object
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create the buffer object');
return;
}
// Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}
// Assign the buffer object to a_Position variable
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// Enable the assignment to a_Position variable
gl.enableVertexAttribArray(a_Position);
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw a point
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3);
}
</script>
</head>
<body onload="main()">
<center style="margin-top:100px">
<canvas id="webgl" width="400" height="400">
Please use a browser that supports "canvas"
</canvas>
</center>
</body>
</html>