-
Notifications
You must be signed in to change notification settings - Fork 113
/
MapNodeHeightGeometry.ts
118 lines (97 loc) · 3.5 KB
/
MapNodeHeightGeometry.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import {BufferGeometry, Float32BufferAttribute, Vector3} from 'three';
import {MapNodeGeometry} from './MapNodeGeometry';
export class MapNodeHeightGeometry extends BufferGeometry
{
/**
* Map node geometry constructor.
*
* @param width - Width of the node.
* @param height - Height of the node.
* @param widthSegments - Number of subdivisions along the width.
* @param heightSegments - Number of subdivisions along the height.
* @param skirt - Skirt around the plane to mask gaps between tiles.
*/
public constructor(width: number = 1.0, height: number = 1.0, widthSegments: number = 1.0, heightSegments: number = 1.0, skirt: boolean = false, skirtDepth: number = 10.0, imageData: ImageData = null, calculateNormals: boolean = true)
{
super();
// Buffers
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
// Build plane
MapNodeGeometry.buildPlane(width, height, widthSegments, heightSegments, indices, vertices, normals, uvs);
const data = imageData.data;
for (let i = 0, j = 0; i < data.length && j < vertices.length; i += 4, j += 3)
{
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// The value will be composed of the bits RGB
const value = (r * 65536 + g * 256 + b) * 0.1 - 1e4;
vertices[j + 1] = value;
}
// Generate the skirt
if (skirt)
{
MapNodeGeometry.buildSkirt(width, height, widthSegments, heightSegments, skirtDepth, indices, vertices, normals, uvs);
}
this.setIndex(indices);
this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
this.setAttribute('normal', new Float32BufferAttribute(normals, 3));
this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
if (calculateNormals)
{
this.computeNormals(widthSegments, heightSegments);
}
}
/**
* Compute normals for the height geometry.
*
* Only computes normals for the surface of the map geometry. Skirts are not considered.
*
* @param widthSegments - Number of segments in width.
* @param heightSegments - Number of segments in height.
*/
public computeNormals(widthSegments: number, heightSegments: number): void
{
const positionAttribute = this.getAttribute('position');
if (positionAttribute !== undefined)
{
// Reset existing normals to zero
let normalAttribute = this.getAttribute('normal');
const normalLength = heightSegments * widthSegments;
for (let i = 0; i < normalLength; i++)
{
normalAttribute.setXYZ(i, 0, 0, 0);
}
const pA = new Vector3(), pB = new Vector3(), pC = new Vector3();
const nA = new Vector3(), nB = new Vector3(), nC = new Vector3();
const cb = new Vector3(), ab = new Vector3();
const indexLength = heightSegments * widthSegments * 6;
for (let i = 0; i < indexLength ; i += 3)
{
const vA = this.index.getX(i + 0);
const vB = this.index.getX(i + 1);
const vC = this.index.getX(i + 2);
pA.fromBufferAttribute(positionAttribute, vA);
pB.fromBufferAttribute(positionAttribute, vB);
pC.fromBufferAttribute(positionAttribute, vC);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
nA.fromBufferAttribute(normalAttribute, vA);
nB.fromBufferAttribute(normalAttribute, vB);
nC.fromBufferAttribute(normalAttribute, vC);
nA.add(cb);
nB.add(cb);
nC.add(cb);
normalAttribute.setXYZ(vA, nA.x, nA.y, nA.z);
normalAttribute.setXYZ(vB, nB.x, nB.y, nB.z);
normalAttribute.setXYZ(vC, nC.x, nC.y, nC.z);
}
this.normalizeNormals();
normalAttribute.needsUpdate = true;
}
}
}