更新于 

层次模型

复杂模型

听到复杂两个字别害怕,再复杂的大模型都是由简单的小模型组成哒

以机器人手臂为例

就像拼乐高一样,大模型的的单位就是这些小零件,你需要知道的就是 有哪些零件拼接关系

乐高积木说明书
乐高积木说明书

要实现这样一个简单的机器人手臂,你需要考虑一下这样几个关节:

部位旋转轴带动部位无影响部位
上臂肩关节前臂、手掌、手指
前臂肘关节手掌、手指上臂
手掌腕关节手指上臂、前臂
手指上臂、前臂、手掌
层次结构模型

最常用的方法就是按 层次顺序-由高到低 逐一绘制。
三维模型各个部件的运动最重要的就是实现:

部件A转动带动部件B转动

单关节模型

  • arm2 前臂
  • joint1 肘关节
  • arm1 上臂
  • 垂直交点 肩关节

单关节模型变换的核心就是 joint1-肘关节

  • 上臂 以肘关节所在的 y轴旋转
  • 前臂 以肘关节所在的 z轴旋转
JointMode
JointMode运行结果
JointMode运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
varying vec4 v_Color;
void main(){
gl_Position = u_MvpMatrix * a_Position;
vec3 lightDirection = normalize(vec3(0.0,0.5,0.7));
vec4 color = vec4( 0.0, 0.4, 0.4, 1.0);
vec3 normal = normalize((u_NormalMatrix * a_Normal).xyz);
float nDotL = max(dot(normal,lightDirection ),0.0);
v_Color = vec4(color.rgb * nDotL + vec3(0.3),color.a);
}
`;

let FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function main() {
let canvas = document.getElementById('webgl');
let gl = getWebGLContext(canvas);
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('failed to init shaders');
return;
}

let n = initVertexBuffers(gl); //set the vertex information

gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);

let u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
let u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');

let vpMatrix = new Matrix4();
vpMatrix.setPerspective(
50, 1.0, 1.0, 100.0
).lookAt(
20, 10, 30, 0, 0, 0, 0, 1, 0
);
document.onkeydown = function (ev) {
keydown(gl,ev,n,u_MvpMatrix,u_NormalMatrix,vpMatrix);
}
draw(gl,n,u_MvpMatrix,u_NormalMatrix,vpMatrix);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function initVertexBuffers(gl) {
var vertices = new Float32Array([
1.5, 10.0, 1.5, -1.5, 10.0, 1.5, -1.5, 0.0, 1.5, 1.5, 0.0, 1.5, // v0-v1-v2-v3 front
1.5, 10.0, 1.5, 1.5, 0.0, 1.5, 1.5, 0.0,-1.5, 1.5, 10.0,-1.5, // v0-v3-v4-v5 right
1.5, 10.0, 1.5, 1.5, 10.0,-1.5, -1.5, 10.0,-1.5, -1.5, 10.0, 1.5, // v0-v5-v6-v1 up
-1.5, 10.0, 1.5, -1.5, 10.0,-1.5, -1.5, 0.0,-1.5, -1.5, 0.0, 1.5, // v1-v6-v7-v2 left
-1.5, 0.0,-1.5, 1.5, 0.0,-1.5, 1.5, 0.0, 1.5, -1.5, 0.0, 1.5, // v7-v4-v3-v2 down
1.5, 0.0,-1.5, -1.5, 0.0,-1.5, -1.5, 10.0,-1.5, 1.5, 10.0,-1.5 // v4-v7-v6-v5 back
]);

// Normal
var normals = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);

// Indices of the vertices
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);

initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT);
initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT);

let indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;

}

function initArrayBuffer(gl, attribute, data, num, type) {
let buffer = gl.createBuffer();
let a_Attribute = gl.getAttribLocation(gl.program, attribute);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Attribute, num, type, false, 0, 0);
gl.enableVertexAttribArray(a_Attribute);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let ANGLE_STEP = 5.0; // the increments of rotation angle
let g_arm1Angle = -90.0;
let g_joint1Angle = 0.0;
function keydown(gl, ev, n, u_MvpMatrix, u_NormalMatrix, vpMatrix) {
// ←→:arm1 ↑↓:arm2
switch (ev.keyCode) {
case 37: g_arm1Angle = (g_arm1Angle - ANGLE_STEP) % 360; break; //←
case 38: if (g_joint1Angle < 135.0) g_joint1Angle += ANGLE_STEP; break; //↑
case 39: g_arm1Angle = (g_arm1Angle + ANGLE_STEP) % 360; break; //→
case 40: if (g_joint1Angle > -135.0) g_joint1Angle -= ANGLE_STEP; break; //↓
default: break;
}
draw(gl,n,u_MvpMatrix,u_NormalMatrix,vpMatrix);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

let g_modelMatrix = new Matrix4(); // Model Matrix
let g_mvpMatrix = new Matrix4();
// count modelMatrix
function draw(gl,n,u_MvpMatrix,u_NormalMatrix,vpMatrix) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Arm1
let arm1Length = 10.0;
g_modelMatrix.setTranslate(0.0, -12.0, 0.0);
g_modelMatrix.rotate(g_arm1Angle, 0.0, 1.0, 0.0);
drawBox(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix);

// Arm2
g_modelMatrix.translate(0.0, arm1Length, 0.0);
g_modelMatrix.rotate(g_joint1Angle, 0.0, 0.0, 1.0);
g_modelMatrix.scale(1.3, 1.0, 1.3);
drawBox(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix);
}

let g_normalMatrix = new Matrix4();
// count mvpMatrix and normalMatrix , then draw the result
function drawBox(gl,n,u_MvpMatrix,u_NormalMatrix,vpMatrix) {
g_mvpMatrix.set(
vpMatrix
).multiply(
g_modelMatrix
);
gl.uniformMatrix4fv(u_MvpMatrix, false, g_mvpMatrix.elements);
g_normalMatrix.setInverseOf(g_modelMatrix);
g_normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix, false, g_normalMatrix.elements);
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
}

多节点模型

  • finger1&finger2 两根手指
  • palm 手掌
  • arm2 前臂
  • arm1 上臂
  • base 基座
变量名对应部位操控键
g_arm1Angle上臂←→
g_joint1Angle肘关节↑↓
g_joint2Angle腕关节xz
g_joint3Angle指张角cv
MultiJointModel
MultiJointModel运行效果
MultiJointModel运行效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function keydown(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix, ev) {
switch (ev.keyCode) {
case 37: //← arm1 clockwise rotation
g_arm1Angle = (g_arm1Angle - ANGLE_STEP) % 360;
break;
case 38: //↑ joint1 open
if (g_joint1Angle < joint1_limit) {
g_joint1Angle += ANGLE_STEP;
}
break;
case 39: //→ arm1 anticlockwise rotation
g_arm1Angle = (g_arm1Angle + ANGLE_STEP) % 360;
break;
case 40: //↓ joint1 close
if (g_joint1Angle > -joint1_limit) {
g_joint1Angle -= ANGLE_STEP;
}
break;
case 67: //c the negative rotation of joint3
if (g_joint3Angle > -joint3_limit) {
g_joint3Angle -= ANGLE_STEP;
}
break;
case 86: //v the positive rotation of joint3
if (g_joint3Angle < joint3_limit) {
g_joint3Angle += ANGLE_STEP;
}
break;
case 88: //x the position rotattion of joint2
g_joint2Angle = (g_joint2Angle + ANGLE_STEP) % 360;
break;
case 90: //z the negative rotattion of joint2
g_joint2Angle = (g_joint2Angle - ANGLE_STEP) % 360;
break;
default: break;
}
draw(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
let baseHeight = 2.0;
let arm1Length = 10.0;
let arm2Length = 10.0;
let palmLength = 2.0;

function draw(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// base
g_modelMatrix.setTranslate(0, -12, 0);
drawBox(gl, n, 10.0, baseHeight, 10.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// arm1
g_modelMatrix.translate(0, baseHeight, 0);
g_modelMatrix.rotate(g_arm1Angle, 0, 1, 0);
drawBox(gl, n, 3.0, arm1Length, 3.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// arm2
g_modelMatrix.translate(0, arm1Length, 0);
g_modelMatrix.rotate(g_joint1Angle, 0, 0, 1);
drawBox(gl, n, 4.0, arm2Length, 4.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// palm
g_modelMatrix.translate(0, arm2Length, 0);
g_modelMatrix.rotate(g_joint2Angle, 0, 1, 0);
drawBox(gl, n, 2.0, palmLength, 6.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// fingers
g_modelMatrix.translate(0, palmLength, 0);

// finger1
pushMatrix(g_modelMatrix);
g_modelMatrix.translate(0, 0, 2.0);
g_modelMatrix.rotate(g_joint3Angle, 1, 0, 0);
drawBox(gl, n, 1.0, 2.0, 1.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);
g_modelMatrix = popMatrix();

// finger2
g_modelMatrix.translate(0.0, 0.0, -2.0);
g_modelMatrix.rotate(-g_joint3Angle, 1, 0, 0);
drawBox(gl, n, 1.0, 2.0, 1.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let g_matrixStack = []; //Array for storing matrix

function pushMatrix(m) {
let m2 = new Matrix4(m);
g_matrixStack.push(m2);
}
function popMatrix() {
return g_matrixStack.pop();
}
function drawBox(gl, n, width, height, depth, vpMatrix, u_MvpMatrix, u_NormalMatrix) {
pushMatrix(g_modelMatrix);
g_modelMatrix.scale(width, height, depth);
g_mvpMatrix.set(vpMatrix).multiply(g_modelMatrix);
g_normalMatrix.setInverseOf(g_modelMatrix);
g_normalMatrix.transpose();
gl.uniformMatrix4fv(u_MvpMatrix, false, g_mvpMatrix.elements);
gl.uniformMatrix4fv(u_NormalMatrix, false, g_normalMatrix.elements);
gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
g_modelMatrix = popMatrix();
}

绘制部件

drawSegments
MultiJoinModel方法概括

总体来说聚焦于 模型矩阵

  • 一切部件的 缓冲区数据 都一样
  • 通过改变 模型矩阵 来绘制出外形不同的部件
  • 低层级绘制使用的模型矩阵需要 基于 高层级的模型矩阵
  • 需要对多个部件进行缩放变换时,需要使用 矩阵管理栈

绘制部件的方法有如下的特性:

  • 对每一个部件都定义一个单独的 缓冲区对象 存储对应顶点数据
  • 各个部件可以根据部件特性选择性 共享 某些数据
MultiJointModel_segment

不同点在于segment方法在main中就引入了 a_Position
因为之后需要使用不同部件的 坐标缓冲区数据

MultiJoinModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function main() {
let canvas = document.getElementById('webgl');
let gl = getWebGLContext(canvas);
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('failed to init shaders');
return;
}
let n = initVertexBuffers(gl);

gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);

let u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
let u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');

let vpMatrix = new Matrix4();
vpMatrix.setPerspective(
50, 1, 1, 100
).lookAt(
20, 10, 30, 0, 0, 0, 0, 1, 0
);

document.onkeydown = function (ev) {
keydown(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix, ev);
}
draw(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix);
}

MultiJointModel_segment

1
2
3
4
5
6
7
8
9
10
11
function main() {
...
let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
let u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
let u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');

document.onkeydown = function (ev) {
keydown(gl, ev, n, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);
}
draw(gl, n, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);
}

不同点在于:

  • ModelJointModel 使用模型矩阵对同一个模型进行拉伸创建不同的部件
  • ModelJointModel_segment 使用不同的缓冲区数据给a_Position重新赋值以创建不同的部件

ModelJointModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function draw(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// base
g_modelMatrix.setTranslate(0, -12, 0);
drawBox(gl, n, 10.0, baseHeight, 10.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// arm1
g_modelMatrix.translate(0, baseHeight, 0);
g_modelMatrix.rotate(g_arm1Angle, 0, 1, 0);
drawBox(gl, n, 3.0, arm1Length, 3.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// arm2
g_modelMatrix.translate(0, arm1Length, 0);
g_modelMatrix.rotate(g_joint1Angle, 0, 0, 1);
drawBox(gl, n, 4.0, arm2Length, 4.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// palm
g_modelMatrix.translate(0, arm2Length, 0);
g_modelMatrix.rotate(g_joint2Angle, 0, 1, 0);
drawBox(gl, n, 2.0, palmLength, 6.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

// fingers
g_modelMatrix.translate(0, palmLength, 0);

// finger1
pushMatrix(g_modelMatrix);
g_modelMatrix.translate(0, 0, 2.0);
g_modelMatrix.rotate(g_joint3Angle, 1, 0, 0);
drawBox(gl, n, 1.0, 2.0, 1.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);
g_modelMatrix = popMatrix();

// finger2
g_modelMatrix.translate(0.0, 0.0, -2.0);
g_modelMatrix.rotate(-g_joint3Angle, 1, 0, 0);
drawBox(gl, n, 1.0, 2.0, 1.0, vpMatrix, u_MvpMatrix, u_NormalMatrix);

}

ModelJointModel_segment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function draw(gl, n, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

g_ModelMatrix.setTranslate(0.0, -12.0, 0.0);
drawSegment(gl, n, g_baseBuffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

g_ModelMatrix.translate(
0.0, baseHeight, 0.0
).rotate(
g_arm1Angle, 0, 1, 0
);
drawSegment(gl, n, g_arm1Buffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

g_ModelMatrix.translate(
0.0, arm1Length, 0.0
).rotate(
g_joint1Angle, 0, 0, 1
);
drawSegment(gl, n, g_arm2Buffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

g_ModelMatrix.translate(
0.0, arm2Length, 0.0
).rotate(
g_joint2Angle, 0, 1, 0
);
drawSegment(gl, n, g_palmBuffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

g_ModelMatrix.translate(
0.0, palmLength, 0.0
);
pushMatrix(g_ModelMatrix);
g_ModelMatrix.translate(
0.0, 0.0, 2.0
).rotate(
g_joint3Angle, 1, 0, 0
);
drawSegment(gl, n, g_fingerBuffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

g_ModelMatrix = popMatrix();
g_ModelMatrix.translate(
0.0, 0.0, -2.0
).rotate(
-g_joint3Angle, 1, 0, 0
);
drawSegment(gl, n, g_fingerBuffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix);

}
  • drawBox 需要根据尺寸对组件进行拉伸,需要通过栈对未拉伸的矩阵进行保存
  • drawSegment 需要根据缓冲区重新对a_Position赋值

ModelJointModel

1
2
3
4
5
6
function drawBox(gl, n, width, height, depth, vpMatrix, u_MvpMatrix, u_NormalMatrix) {
pushMatrix(g_modelMatrix);
g_modelMatrix.scale(width, height, depth);
...
g_modelMatrix = popMatrix();
}

ModelJointModel_segment

1
2
3
4
5
6
7
function drawSegment(gl, n, buffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix) {
// write segment's data
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT,false, 0, 0);
gl.enableVertexAttribArray(a_Position);
...
}

segment方法不在这里对 a_Position 进行赋值,
这里需要对所有部件的缓冲区进行 数据写入,但是不对a_Position进行赋值。

MultiJoinModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function initVertexBuffers(gl) {
var vertices = new Float32Array([
0.5, 1.0, 0.5, -0.5, 1.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, 0.5, // v0-v1-v2-v3 front
0.5, 1.0, 0.5, 0.5, 0.0, 0.5, 0.5, 0.0,-0.5, 0.5, 1.0,-0.5, // v0-v3-v4-v5 right
0.5, 1.0, 0.5, 0.5, 1.0,-0.5, -0.5, 1.0,-0.5, -0.5, 1.0, 0.5, // v0-v5-v6-v1 up
-0.5, 1.0, 0.5, -0.5, 1.0,-0.5, -0.5, 0.0,-0.5, -0.5, 0.0, 0.5, // v1-v6-v7-v2 left
-0.5, 0.0,-0.5, 0.5, 0.0,-0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, // v7-v4-v3-v2 down
0.5, 0.0,-0.5, -0.5, 0.0,-0.5, -0.5, 1.0,-0.5, 0.5, 1.0,-0.5 // v4-v7-v6-v5 back
]);

// Normal
var normals = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);

// Indices of the vertices
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);

initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT);
initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT);

let indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;

}

function initArrayBuffer(gl, attribute, data, num, type) {
let buffer = gl.createBuffer();
let a_Attribute = gl.getAttribLocation(gl.program, attribute);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Attribute, num, type, false, 0, 0);
gl.enableVertexAttribArray(a_Attribute);
}

MultiJointModel_segment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
function initVertexBuffers(gl) {
var vertices_base = new Float32Array([ // Base(10x2x10)
]);
var vertices_arm1 = new Float32Array([ // Arm1(3x10x3)
]);
var vertices_arm2 = new Float32Array([ // Arm2(4x10x4)
]);
var vertices_palm = new Float32Array([ // Palm(2x2x6)
]);
var vertices_finger = new Float32Array([ // Fingers(1x2x1)
]);
// Normal
var normals = new Float32Array([
]);
// Indices of the vertices
var indices = new Uint8Array([
]);

// Write coords to buffer, but don't assign to attribute variables
// Just like regist
g_baseBuffer = initArrayBufferForLaterUse(gl, vertices_base, 3, gl.FLOAT);
g_arm1Buffer = initArrayBufferForLaterUse(gl, vertices_arm1, 3, gl.FLOAT);
g_arm2Buffer = initArrayBufferForLaterUse(gl, vertices_arm2, 3, gl.FLOAT);
g_palmBuffer = initArrayBufferForLaterUse(gl, vertices_palm, 3, gl.FLOAT);
g_fingerBuffer = initArrayBufferForLaterUse(gl, vertices_finger, 3, gl.FLOAT);

// write normals to a buffer ,assign it to a_Normal
initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT);

let indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}

// regist buffer
function initArrayBufferForLaterUse(gl, data, num, type) {
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// set the num and type in advance
// instead of use vertexAttribPointer
buffer.num = num;
buffer.type = type;
return buffer;
}

// regist buffer and assign
function initArrayBuffer(gl, attribute, data, num, type) {
let buffer = gl.createBuffer();
let a_Attribute = gl.getAttribLocation(gl.program, attribute);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.vertexAttribPointer(a_Attribute, num, type, false, 0, 0);
gl.enableVertexAttribArray(a_Attribute);
}