1.绘制立方体:
使用gl.drawArrays方法以gl.TRIANGLES方式绘制需要定义36个顶点,以gl.TRIANGLE_FAN绘制需要24个顶点,但是需要调用6次drawArrays方法。WebGL提供了解决方案:gl.drawElements();
API:gl.drawElements(mode,count,type,offset),避免重复定义顶点,保持顶点数量最小
mode:指定绘图方式
count:绘制顶点个数(整型)
type:指定索引值数据类型gl.UNSIGNED_BYTE或gl.UNSIGNED_SHORT
offset:指定索引数组中开始绘制的位置,以字节为单位
该绘制方法先从ELEMENT_ARRAY_BUFFER中读取顶点索引,再索引到ARRAY_BUFFER中的顶点坐标,然后调用着色器进行绘制。向ELEMENT_ARRAY_BUFFER写入数据的方法和向ARRAY_BUFFER写入数据方法相同。顶点着色器的执行次数由ELEMENT_ARRAY_BUFFER中索引的个数决定
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_mvpMatrix;\n' +
'varying vec4 v_Color;\n' +
'void main(){\n' +
'gl_Position = u_mvpMatrix * a_Position;\n' +
'v_Color = a_Color;\n' +
'}\n';
var FSHADER_SOURCE =
'precision mediump float;\n' +
'varying vec4 v_Color;\n' +
'void main(){\n' +
'gl_FragColor = v_Color;\n' +
'}\n';
function main()
{
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("着色器初始化失败");
}
var n = initVertexBuffers(gl);
console.log("n是"+n);
//开启深度检测
gl.enable(gl.DEPTH_TEST);
gl.clearColor(0,0,0,1);
var mvpMatrix = new Matrix4();
var u_mvpMatrix = gl.getUniformLocation(gl.program,'u_mvpMatrix');
if(!u_mvpMatrix){
console.log("u_mvpMatrix变量获取失败");
}
mvpMatrix.setPerspective(30,canvas.width/canvas.height,1,100);
mvpMatrix.lookAt(3,3,7,0,0,0,0,1,0);
gl.uniformMatrix4fv(u_mvpMatrix,false,mvpMatrix.elements);
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}
function initVertexBuffers(gl)
{
var verticesColors = new Float32Array([
1.0,1.0,1.0,1.0,1.0,1.0,
-1.0,1.0,1.0,1.0,0.0,1.0,
-1.0,-1.0,1.0,1.0,0.0,0.0,
1.0,-1.0,1.0,1.0,1.0,0.0,
1.0,-1.0,-1.0,0.0,1.0,0.0,
1.0,1.0,-1.0,0.0,1.0,1.0,
-1.0,1.0,-1.0,0.0,0.0,1.0,
-1.0,-1.0,-1.0,0.0,0.0,0.0
]);
var FSIZE = verticesColors.BYTES_PER_ELEMENT;
var indices = new Uint8Array([ //当顶点个数多于256时应该用Uint16Array数组
0,1,2,0,2,3,
0,3,4,0,4,5,
0,5,6,0,6,1,
1,6,7,1,7,2,
7,4,3,7,3,2,
4,7,6,4,6,5
]);
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
var a_Color = gl.getAttribLocation(gl.program,'a_Color');
if(a_Position<0){
console.log("获取变量a_Position位置失败");
}
if(a_Color<0) {
console.log("获取变量a_Color位置失败");
}
var vertexColorBuffer = gl.createBuffer();
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,verticesColors,gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Position,3,gl.FLOAT,false,FSIZE*6,0);
gl.enableVertexAttribArray(a_Position);
gl.vertexAttribPointer(a_Color,3,gl.FLOAT,false,FSIZE*6,FSIZE*3);
gl.enableVertexAttribArray(a_Color);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);
return indices.length;
}
2.为立方体每个表面指定不同颜色
注意:指定顶点颜色后,着色器会自动内插出面上每个片元的颜色值,但是每个顶点由三个表面共用,那就需要为一个顶点指定三次颜色,所以每个顶点都需要定义三次即24个点。
将颜色单独存在一个缓冲区,颜色缓冲区与顶点坐标缓冲区根据存储的顺序对应,索引缓冲区根据索引值和顶点坐标缓冲区对应。
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'varying vec4 v_Color;\n' +
'uniform mat4 u_mvpMatrix;\n' +
'void main(){\n' +
'gl_Position = u_mvpMatrix * a_Position;\n' +
'v_Color = a_Color;\n' +
'}\n';
var FSHADER_SOURCE =
'precision mediump float;\n' +
'varying vec4 v_Color;\n' +
'void main(){\n' +
'gl_FragColor = v_Color;\n' +
'}\n';
function main()
{
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl');
if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("着色器初始化异常");
}
//开启深度检测
gl.enable(gl.DEPTH_TEST);
gl.clearColor(0,0,0,1);
var n = initVertexBuffers(gl);
var mvpMatrix = new Matrix4();
var u_mvpMatrix = gl.getUniformLocation(gl.program,'u_mvpMatrix');
if(!u_mvpMatrix){
console.log("u_mvpMatrix变量获取失败");
}
draw(gl,mvpMatrix,u_mvpMatrix,n);
document.onkeydown = function(ev){
keyDown(gl,ev,n,mvpMatrix,u_mvpMatrix);
}
}
var HORZ_ANGLE = 0,STRIGHT_ANGLE = 0;
function keyDown(gl,ev,n,mvpMatrix,u_mvpMatrix)
{
console.log(ev.keyCode);
if(ev.keyCode == 39){
HORZ_ANGLE += 5;
}else if(ev.keyCode == 37) {
HORZ_ANGLE -= 5;
}else if(ev.keyCode == 38) {
STRIGHT_ANGLE -= 5;
}else if(ev.keyCode == 40){
STRIGHT_ANGLE += 5;
}
draw(gl,mvpMatrix,u_mvpMatrix,n);
}
function initVertexBuffers(gl)
{
var vertices = new Float32Array([
1.0,1.0,1.0, -1.0,1.0,1.0, -1.0,-1.0,1.0, 1.0,-1.0,1.0, //前面顶点
1.0,-1.0,-1.0,1.0,1.0,-1.0, 1.0,1.0,1.0, 1.0,-1.0,1.0, //右面顶点
1.0,-1.0,-1.0, 1.0,1.0,-1.0,-1.0,1.0,-1.0, -1.0,-1.0,-1.0,//后面顶点
-1.0,-1.0,-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0, -1.0,-1.0,1.0, //左面顶点
1.0,1.0,1.0, 1.0,1.0,-1.0, -1.0,1.0,-1.0, -1.0,1.0,1.0, //顶面顶点
1.0,-1.0,1.0, 1.0,-1.0,-1.0, -1.0,-1.0,-1.0, -1.0,-1.0,1.0
]);
var colors = new Float32Array([
0.4,0.4,1.0, 0.4,0.4,1.0, 0.4,0.4,1.0, 0.4,0.4,1.0, //前面的顶点颜色
0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, 0.4,1.0,0.4, //右面顶点颜色
1.0,0.4,0.4, 1.0,0.4,0.4, 1.0,0.4,0.4, 1.0,0.4,0.4, //后面顶点颜色
1.0,1.0,0.4, 1.0,1.0,0.4, 1.0,1.0,0.4, 1.0,1.0,0.4, //左面顶点颜色
1.0,0.4,1.0, 1.0,0.4,1.0, 1.0,0.4,1.0, 1.0,0.4,1.0, //顶面顶点颜色
0.4,1.0,1.0, 0.4,1.0,1.0, 0.4,1.0,1.0, 0.4,1.0,1.0 //底面顶点颜色
]);
var indices = new Uint8Array([
0,1,2,0,2,3, //前面的顶点索引
4,5,6,4,6,7, //右面顶点索引
8,9,10,8,10,11, //后面顶点索引
12,13,14,12,14,15, //左面顶点索引
16,17,18,16,18,19, //顶面顶点索引
20,21,22,20,22,23 //底面顶点索引
]);
var FSIZE = vertices.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(gl.program,'a_Position');
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);
initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position');
initArrayBuffer(gl,colors,3,gl.FLOAT,'a_Color');
return indices.length;
}
function initArrayBuffer(gl,data,num,type,attribute)
{
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
var a_attribute = gl.getAttribLocation(gl.program,attribute);
gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
gl.enableVertexAttribArray(a_attribute);
return true;
}
function draw(gl,mvpMatrix,u_mvpMatrix,n)
{
mvpMatrix.setPerspective(30,1,1,100);
mvpMatrix.lookAt(3,3,7,0,0,0,0,1,0);
mvpMatrix.rotate(HORZ_ANGLE,0,1,0);
mvpMatrix.rotate(STRIGHT_ANGLE,1,0,0);
gl.uniformMatrix4fv(u_mvpMatrix,false,mvpMatrix.elements);
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}