1.demo效果
如上,通过顶点索引绘制出了一个渐变色的立方体
2. 顶点索引原理
如上,立方体有8个顶点,v0~v7;6个面,前、后、上、下、左、右;以最前面的面为例,由四个顶点v0-v1-v2-v3拼出的两个三角形组成,这两个三角形使用的顶点索引分别是 (0,1,2)和(0,2,3)。通过三角形的顶点索引,可以取到对应索引的顶点坐标和颜色信息。
创建顶点信息和索引信息示例如下
const verticesAndColors = new Float32Array([
1.0, 1.0, 1.0, 1.0, 1.0, 1.0,1.0, //v0 white
-1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0,//v1 品红
-1.0, -1.0, 1.0, 1.0, 0.0, 0.0,1.0, //v2 红色
1.0, -1.0, 1.0, 1.0, 1.0, 0.0,1.0, //v3 黄色
1.0, -1.0, -1.0, 0.0, 1.0, 0.0,1.0, //v4
1.0, 1.0, -1.0, 0.0, 1.0, 1.0,1, //v5
-1.0, 1.0, -1.0, 0.0, 0.0, 1.0,1, //v6
-1.0, -1.0, -1.0, 0.0, 0.0, 0.0,1, //v7
]);
const indices = new Uint8Array([
0, 1, 2, 0, 2, 3, //front
0, 3, 4, 0, 4, 5, //right
0, 5, 6, 0, 6, 1, //up
1, 6, 7, 1, 7, 2, //left
7, 4, 3, 7, 3, 2, //bottom
4, 7, 6, 4, 6, 5 //behind
]);
3.gl.drawElements() 方法
函数功能:执行着色器,按照mode参数指定的方式,根据gl.ELEMENT_ARRAY_BUFFER的缓冲区的顶点索引绘制图形
--------------------------------------------------------------------------
调用示例:gl.drawArrays(mode, count, type, offset)
--------------------------------------------------------------------------
参数
mode 指定绘制的方式,可以接收以下常量符号:
gl.POINTS,gl.LINES,gl.LINE_STRIP,gl.LINE_LOOP
gl.TRIANGLES,gl.TRIANGLE_STRIP,gl.TRIANGLE_FAN
count 指定绘制顶点的个数
type 指定索引值数据类型,可以以下值
gl.UNSIGNED_BYTE
gl.UNSIGNED_SHORT
offset 指定索引数组中开始绘制的位置,以字节为单位
--------------------------------------------------------------------------
返回值 无
--------------------------------------------------------------------------
错 误 INVALID_ENUM 传入的mode参数不是指定参数
INVALID_VALUE 参数count或offset是负数
第一个参数mode说明
gl.drawArray()方法可以绘制各种图形,它的第一个参数可以取众多常量:gl.POINTS,gl.LINES,gl.LINE_STRIP,gl.LINE_LOOP,gl.TRIANGLES,gl.TRIANGLE_STRIP,gl.TRIANGLE_FAN,接下来通过一张图来解释
4.demo代码
const VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
varying vec4 v_Color;
void main() {
gl_Position = u_ProjMatrix* u_ViewMatrix*a_Position;
v_Color = a_Color;
}
`;
const FSHADER_SOURCE = `
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`;
const main = () => {
//获取绘制dom
const canvas = document.getElementById("webgl");
//获取canvas上下文
const gl = canvas.getContext("webgl");
gl.enable(gl.DEPTH_TEST);
//初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
return console.log("Failed to initialize shaders.");
}
const initVertexBuffers = (gl) => {
const u_ViewMatrix = gl.getUniformLocation(gl.program, "u_ViewMatrix");
const u_ProjMatrix = gl.getUniformLocation(gl.program, "u_ProjMatrix");
const viewMatrix = new Matrix4();
const projMatrix = new Matrix4();
viewMatrix.setLookAt(3, 3, 7, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
projMatrix.setPerspective(30, canvas.width/canvas.height, 1.0, 100);
gl.uniformMatrix4fv(u_ProjMatrix,false,projMatrix.elements)
//类型化数组设置顶点坐标
const verticesAndColors = new Float32Array([
1.0, 1.0, 1.0, 1.0, 1.0, 1.0,1.0, //v0 white
-1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0,//v1 品红
-1.0, -1.0, 1.0, 1.0, 0.0, 0.0,1.0, //v2 红色
1.0, -1.0, 1.0, 1.0, 1.0, 0.0,1.0, //v3 黄色
1.0, -1.0, -1.0, 0.0, 1.0, 0.0,1.0, //v4
1.0, 1.0, -1.0, 0.0, 1.0, 1.0,1, //v5
-1.0, 1.0, -1.0, 0.0, 0.0, 1.0,1, //v6
-1.0, -1.0, -1.0, 0.0, 0.0, 0.0,1, //v7
]);
const indices = new Uint8Array([
0, 1, 2, 0, 2, 3, //front
0, 3, 4, 0, 4, 5, //right
0, 5, 6, 0, 6, 1, //up
1, 6, 7, 1, 7, 2, //left
7, 4, 3, 7, 3, 2, //bottom
4, 7, 6, 4, 6, 5 //behind
]);
// const n = verticesAndColors.length/6; //点的个数
//创建缓冲区对象
const vertexBuffer = gl.createBuffer();
//创建IndexBuffer
const indicesBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log("Failed to create the buffer object");
return -1;
}
//将缓冲区对象绑定到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
//向缓冲区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, verticesAndColors, gl.STATIC_DRAW);
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
const a_Color = gl.getAttribLocation(gl.program, "a_Color");
const FSIZE = verticesAndColors.BYTES_PER_ELEMENT;
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
//将缓冲区对象分配给a_Position变量
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false,FSIZE * 7, 0);
//链接a_Position变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);
gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, FSIZE * 7, FSIZE * 3);
gl.enableVertexAttribArray(a_Color);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW)
return indices.length;
};
const n = initVertexBuffers(gl);
if (n < 0) {
console.error("n<0");
return;
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
//清空canvas
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//绘制一个点
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE,0);
};
main();