/
sphere.ts
81 lines (69 loc) · 1.91 KB
/
sphere.ts
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
* @packageDocumentation
* @module 3d/primitive
*/
import { Vec3 } from '../math';
import { IGeometry, IGeometryOptions } from './define';
/**
* @zh
* 球参数选项。
*/
interface ISphereOptions extends IGeometryOptions {
segments: number;
}
/**
* @en
* Generate a shpere with radius 0.5.
* @zh
* 生成一个球。
* @param radius 球半径。
* @param options 参数选项。
*/
export default function sphere (radius = 0.5, opts: RecursivePartial<ISphereOptions> = {}): IGeometry {
const segments = opts.segments !== undefined ? opts.segments : 32;
// lat === latitude
// lon === longitude
const positions: number[] = [];
const normals: number[] = [];
const uvs: number[] = [];
const indices: number[] = [];
const minPos = new Vec3(-radius, -radius, -radius);
const maxPos = new Vec3(radius, radius, radius);
const boundingRadius = radius;
for (let lat = 0; lat <= segments; ++lat) {
const theta = lat * Math.PI / segments;
const sinTheta = Math.sin(theta);
const cosTheta = -Math.cos(theta);
for (let lon = 0; lon <= segments; ++lon) {
const phi = lon * 2 * Math.PI / segments - Math.PI / 2.0;
const sinPhi = Math.sin(phi);
const cosPhi = Math.cos(phi);
const x = sinPhi * sinTheta;
const y = cosTheta;
const z = cosPhi * sinTheta;
const u = lon / segments;
const v = lat / segments;
positions.push(x * radius, y * radius, z * radius);
normals.push(x, y, z);
uvs.push(u, v);
if ((lat < segments) && (lon < segments)) {
const seg1 = segments + 1;
const a = seg1 * lat + lon;
const b = seg1 * (lat + 1) + lon;
const c = seg1 * (lat + 1) + lon + 1;
const d = seg1 * lat + lon + 1;
indices.push(a, d, b);
indices.push(d, c, b);
}
}
}
return {
positions,
indices,
normals,
uvs,
minPos,
maxPos,
boundingRadius,
};
}