### 基础图元

#### 点

const vertex = new Float32Array([0.0, 0.0, 0.0]);
...
webgl.drawArrays(webgl.POINTS, 0, 1);


#### 线

// 初始化两条点 A1 A2
const vertex = new Float32Array([0.5, 0.0, 0.0, -0.5, 0.0, 0.0, 0.0, 0.5, 0.0]);
const color = new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]);
...
webgl.drawArrays(webgl.LINES, 0, 4);



#### 三角形

const vertex = new Float32Array([
0.5, 0.0, 0.0,
-0.5, 0.0, 0.0,
0.0, 0.5, 0.0
]);
...
webgl.drawArrays(webgl.TRIANGLES, 0, 3);


### 平面图形-2D

#### 矩形

const vertex = new Float32Array([
0.0, 0.3, 0.0, // 1
0.0, 0.0, 0.0, // 2
0.3, 0.3, 0.0, // 3
0.3, -0.3, 0.0 // 4
]);
...
webgl.drawArrays(webgl.TRIANGLE_STRIP, 0, 4);


#### 五角星

//一共十个点
const counts = 10,
// 最远的点和最短的点到中心的距离
radius = 0.45,
min_radis = 0.25,
//将夹角转换成弧度
radiation = (Math.PI / 180) * (360 / 10),
//中心位置
center = [0.0, 0.0];

let vertexs: number[] = center;
let color: number[] = [1.0, 1.0, 0.0];
for (let index = 0; index <= counts; index++) {
// 顶点的位置
let x = Math.sin(radiation * index) * radius;
let y = Math.cos(radiation * index) * radius;
// 内圈顶点的位置
if (index % 2 === 0) {
x = Math.sin(radiation * index) * min_radis;
y = Math.cos(radiation * index) * min_radis;
}
vertexs.push(x);
vertexs.push(y);
color.push(...[1.0, 1.0, 0.0]);
}

...

webgl.drawArrays(webgl.TRIANGLE_FAN, 0, count);


#### 窗格

function createVertex (square:number) {
square =  square * 10;
let vertex:number[] = [];
let pointer: number[] = [];
let linePointer: number[] = [];
// 画出每个格子在x和z轴上的点
for (let indexX = 0; indexX < square; indexX++) {// x
for (let indexZ = 0; indexZ < square; indexZ++) {// z
vertex.push(indexX * 0.1,  0, -indexZ * 0.1);
}
linePointer.push(indexX * square, (indexX + 1) * square - 1);
}
// 画出通过TRIANGLE_STRIP 的方式指定索引
for (let indexX = 0; indexX < Math.pow(square, 2) - square; indexX++) {// z
pointer.push(indexX, indexX + square);

}

// 三角形描边
linePointer = linePointer.concat(pointer);

return {
vertexArray: new Float32Array(vertex),
pointerArray: new Uint16Array(pointer),
pointerLineArray: new Uint16Array(linePointer),
count: pointer.length,
lineCount: linePointer.length
};
}

....
webgl.drawElements(webgl.TRIANGLE_STRIP, count, webgl.UNSIGNED_SHORT, 0);
webgl.drawElements(webgl.LINES, lineCount, webgl.UNSIGNED_SHORT, 0);


#### 圆形

const radius: number = 0.5, resolution: number = 60;
const count = resolution + 2;

//将夹角转换成弧度
const radiation = (Math.PI / 180) * (360 / resolution),
//中心位置
center = [0.0, 0.0];
let vertexs: number[] = center;
let color: number[] = [0.0, 0.0, 1.0];
for (let index = 0; index <= resolution; index++) {
let x = Math.sin(radiation * index) * radius;
let y = Math.cos(radiation * index) * radius;
vertexs.push(x);
vertexs.push(y);
color.push(0.0, 0.0, 1.0);
}
...
webgl.drawArrays(webgl.TRIANGLE_FAN, 0, count);


### 立体模型-3D

1. 内存使用大小，使用drawElements会带来额外的索引字节存储空间，但是使用drawArrays则需要更多的顶点字节存储空间。所以你需要综合考量。
2. 方法的灵活性。就我而言使用drawElements更能帮助我任性定位顶点索引，不会因为某些混乱的判断而画错图形。简单来说drawElements在绘制三维图形时根据有灵活性。
3. 自己的习惯。在充分考虑前面两个因素后，你最后只需要决定你喜欢的方式来绘制即可，根据自己的习惯也能介绍你的开发时间。

#### 立方体

  //    v6----- v5
//   /|      /|
//  v1------v0|
//  | |     | |
//  | |v7---|-|v4
//  |/      |/
//  v2------v3

const vertex = new Float32Array([
-0.5, -0.5, 0.5,
-0.5, 0.5, 0.5,
0.5, 0.5, 0.5,
0.5, -0.5, 0.5,

-0.5, -0.5, -0.5,
-0.5, 0.5, -0.5,
0.5, 0.5, -0.5,
0.5, -0.5, -0.5,
]);

const pointer = new Uint16Array([
0, 1, 2, 2, 0, 3, // FRONT,
0, 4, 1, 1, 4, 5, // LEFT
2, 3, 7, 2, 7, 6, // RIGHT
4, 5, 6, 4, 6, 7, // BACK
4, 0, 7, 0, 7, 3, // BOTTOM
1, 5, 6, 1, 6, 2 // TOP
]);
...
webgl.drawElements(webgl.TRIANGLES, count, webgl.UNSIGNED_SHORT, 0);


#### 圆柱体

const HEIGHT = height,
TOP = [0, HEIGHT, 0],
RESOLUTION = 50,
BOTTOM = [0, -1, 0],
theta = ((360 / RESOLUTION) * Math.PI) / 180;
let vertexs: number[] = [];
// 分别计算出上下表面圆边上的点
for (let index = 0; index < RESOLUTION; index++) {
// top circle
const x = Math.cos(theta * index) * radiusB;
const z = Math.sin(theta * index) * radiusB;
// bottom circle
const x1 = Math.cos(theta * index) * radiusT;
const z1 = Math.sin(theta * index) * radiusT;
// 上面的圆点每一隔得y轴高度都是统一的，同理，下表面的的圆的y轴也是固定的。
vertexs.push(x, HEIGHT, z, x1, -1, z1);
}
// 其他点1~resolution 底部中心点的位置 resolution + 1; 顶点位置 resolution，
vertexs.push(...BOTTOM, ...TOP);


let pointer: number[] = [];
//斜边
for (let index = 0; index < RESOLUTION * 2; index++) {
pointer.push(index); // 顶部点的位；
/* 通过 % 实现当Y Z大于resultion的时候取绝对值，实现点位的循环。
如：x =40 时 x 为 0  或者x = 41时，x 为 1；
因为矩形的最后一个三角面点需要和第一个点和第二个点进行合并。
*/
pointer.push((index + 1) % (RESOLUTION * 2), (index + 2) % (RESOLUTION * 2));
}

//底边
for (let index = 0; index < RESOLUTION; index++) {
const step = (2 * index + 1) % (2 * RESOLUTION);
const step2 = (2 * (index + 1) + 1) % (2 * RESOLUTION);
// 永远是底部中心点开始的
pointer.push(step);
pointer.push(RESOLUTION + 1); // 顶部中心点的在vertexs中的位置 即 1 + RESOLUTION
pointer.push(step2);
}

//顶边
for (let index = 0; index < RESOLUTION; index++) {
const step = (2 * index + 2) % (2 * RESOLUTION);
const step2 = (2 * (index + 2)) % (2 * RESOLUTION);
// 永远是底部中心点开始的
pointer.push(step);
pointer.push(RESOLUTION); // 底部中心点的在vertexs中的位置 即 RESOLUTION
pointer.push(step2);
}

...
webgl.drawElements(webgl.TRIANGLES, pointer.length, webgl.UNSIGNED_SHORT, 0);


#### 球体

const RADIUS = radius, RESOLUTION = resolution;
const theta = (180 / RESOLUTION) * (Math.PI / 180);
const beta = (360 / RESOLUTION) * (Math.PI / 180);
//计算出圆体以及表面线条的各个点的位置
let vertexs:number[] = [];
for (let index = 0; index <= RESOLUTION; index++) {
// 同等高度的Y值 O1-O2
const y = Math.cos(theta * index) * RADIUS;
// 底边作为斜边的长度 O2-A
const d = Math.sin(theta * index) * RADIUS;
for (let index1 = 0; index1 <= RESOLUTION; index1++) {
// 斜边的余弦即是x轴的距离 O1-c
const x = Math.cos(beta * index1) * d;
// 斜边的正弦即是Z轴的距离 B-C
const z = Math.sin(beta * index1) * d;
vertexs.push(x, y, z);
}
}


    /* 计算出顶点的位置为 [0, 1,..... 一个循环之后, RESOLUTION, RESOLUTION + 1]
我们需要连接的是 0, 1, RESOLUTION 顶点的位置拼凑成一个三角形
*/
for(var index = 0; index < Math.pow(RESOLUTION, 2); index ++)
{
pointer.push(index); // 本行第一个
pointer.push(index + RESOLUTION + 1); // 下一行第一个
pointer.push(index + 1); // 本行第二个

pointer.push(index + 1); // 本行第二个
pointer.push(index + RESOLUTION + 1); // 下一行第一个
pointer.push(index + RESOLUTION + 2); // 下一行第二个

//到此，一个四边形被拼凑成功
}

webgl.drawElements(webgl.TRIANGLES, pointer.length, webgl.UNSIGNED_SHORT, 0);


### 总结

posted on 2021-11-02 11:47  chen·yan  阅读(209)  评论(0编辑  收藏  举报