@niivue/niivue 0.22.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -23
- package/dist/niivue.es.js +108187 -10401
- package/dist/niivue.umd.js +506 -94
- package/package.json +11 -2
- package/src/cmaps/index.js +1 -0
- package/src/cmaps/turbo.json +9 -0
- package/src/colortables.js +79 -0
- package/src/index.html +45 -27
- package/src/indexDraw.html +191 -0
- package/src/logger.js +5 -0
- package/src/meshes.html +161 -0
- package/src/niivue-object3D.js +243 -29
- package/src/niivue-shader3D.js +6 -0
- package/src/niivue.js +2577 -648
- package/src/nvimage.js +1821 -153
- package/src/nvmesh.js +3351 -0
- package/src/shader-srcs.js +565 -11
- package/src/shader.js +11 -2
- package/src/AIL.nii.gz +0 -0
- package/src/hippo.nii.gz +0 -0
- package/src/mni152.nii.gz +0 -0
package/src/niivue-object3D.js
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { mat4, vec3 } from "gl-matrix";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @class NiivueObject3D
|
|
5
|
+
* @type NiivueObject3D
|
|
6
|
+
* @typedef NiivueObject3D
|
|
7
|
+
* @property {Shader[]} renderShaders
|
|
8
|
+
* @property {boolean} isVisible
|
|
9
|
+
* @property {WebGLVertexArrayObject} vertexBuffer
|
|
10
|
+
* @property {number} indexCount
|
|
11
|
+
* @property {WebGLVertexArrayObject} indexBuffer
|
|
12
|
+
* @property {WebGLVertexArrayObject} textureCoordinateBuffer
|
|
13
|
+
* @property {number} mode
|
|
14
|
+
* @description Object rendered with WebGL
|
|
15
|
+
* @constructor
|
|
16
|
+
* @param {number} id
|
|
17
|
+
* @param {WebGLVertexArrayObject} vertexBuffer
|
|
18
|
+
* @param {number} mode
|
|
19
|
+
* @param {number} indexCount
|
|
20
|
+
* @param {WebGLVertexArrayObject} indexBuffer
|
|
21
|
+
* @param {WebGLVertexArrayObject} textureCoordinateBuffer
|
|
22
|
+
**/
|
|
3
23
|
export var NiivueObject3D = function (
|
|
4
24
|
id,
|
|
5
25
|
vertexBuffer,
|
|
6
26
|
mode,
|
|
7
27
|
indexCount,
|
|
8
28
|
indexBuffer = null,
|
|
9
|
-
|
|
29
|
+
vao = null
|
|
10
30
|
) {
|
|
11
31
|
this.BLEND = 1;
|
|
12
32
|
this.CULL_FACE = 2;
|
|
13
33
|
this.CULL_FRONT = 4;
|
|
14
34
|
this.CULL_BACK = 8;
|
|
15
35
|
this.ENABLE_DEPTH_TEST = 16;
|
|
16
|
-
|
|
36
|
+
this.sphereIdx = [];
|
|
37
|
+
this.sphereVtx = [];
|
|
17
38
|
this.renderShaders = [];
|
|
18
|
-
this.pickingShader = null;
|
|
19
39
|
this.isVisible = true;
|
|
20
40
|
this.isPickable = true;
|
|
21
41
|
this.vertexBuffer = vertexBuffer;
|
|
22
42
|
this.indexCount = indexCount;
|
|
23
43
|
this.indexBuffer = indexBuffer;
|
|
24
|
-
this.
|
|
44
|
+
this.vao = vao;
|
|
25
45
|
this.mode = mode;
|
|
26
46
|
|
|
27
47
|
this.glFlags = 0;
|
|
@@ -33,7 +53,7 @@ export var NiivueObject3D = function (
|
|
|
33
53
|
((id >> 24) & 0xff) / 255.0,
|
|
34
54
|
];
|
|
35
55
|
|
|
36
|
-
this.modelMatrix =
|
|
56
|
+
this.modelMatrix = mat4.create();
|
|
37
57
|
this.scale = [1, 1, 1];
|
|
38
58
|
this.position = [0, 0, 0];
|
|
39
59
|
this.rotation = [0, 0, 0];
|
|
@@ -65,7 +85,8 @@ NiivueObject3D.generateCrosshairs = function (
|
|
|
65
85
|
geometry.vertexBuffer,
|
|
66
86
|
gl.TRIANGLES,
|
|
67
87
|
geometry.indexCount,
|
|
68
|
-
geometry.indexBuffer
|
|
88
|
+
geometry.indexBuffer,
|
|
89
|
+
geometry.vao
|
|
69
90
|
);
|
|
70
91
|
};
|
|
71
92
|
|
|
@@ -80,14 +101,14 @@ NiivueObject3D.generateCrosshairsGeometry = function (
|
|
|
80
101
|
) {
|
|
81
102
|
let vertices = [];
|
|
82
103
|
let indices = [];
|
|
83
|
-
let start =
|
|
84
|
-
let dest =
|
|
104
|
+
let start = vec3.fromValues(xyzMin[0], xyzMM[1], xyzMM[2]);
|
|
105
|
+
let dest = vec3.fromValues(xyzMax[0], xyzMM[1], xyzMM[2]);
|
|
85
106
|
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
86
|
-
start =
|
|
87
|
-
dest =
|
|
107
|
+
start = vec3.fromValues(xyzMM[0], xyzMin[1], xyzMM[2]);
|
|
108
|
+
dest = vec3.fromValues(xyzMM[0], xyzMax[1], xyzMM[2]);
|
|
88
109
|
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
89
|
-
start =
|
|
90
|
-
dest =
|
|
110
|
+
start = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMin[2]);
|
|
111
|
+
dest = vec3.fromValues(xyzMM[0], xyzMM[1], xyzMax[2]);
|
|
91
112
|
NiivueObject3D.makeCylinder(vertices, indices, start, dest, radius, sides);
|
|
92
113
|
//console.log('i:',indices.length / 3, 'v:',vertices.length / 3);
|
|
93
114
|
|
|
@@ -100,19 +121,29 @@ NiivueObject3D.generateCrosshairsGeometry = function (
|
|
|
100
121
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
101
122
|
gl.bufferData(
|
|
102
123
|
gl.ELEMENT_ARRAY_BUFFER,
|
|
103
|
-
new
|
|
124
|
+
new Uint32Array(indices),
|
|
104
125
|
gl.STATIC_DRAW
|
|
105
126
|
);
|
|
106
127
|
|
|
128
|
+
let vao = gl.createVertexArray();
|
|
129
|
+
gl.bindVertexArray(vao);
|
|
130
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
|
|
131
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
132
|
+
//vertex position: 3 floats X,Y,Z
|
|
133
|
+
gl.enableVertexAttribArray(0);
|
|
134
|
+
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
|
|
135
|
+
gl.bindVertexArray(null); // https://stackoverflow.com/questions/43904396/are-we-not-allowed-to-bind-gl-array-buffer-and-vertex-attrib-array-to-0-in-webgl
|
|
136
|
+
|
|
107
137
|
return {
|
|
108
138
|
vertexBuffer,
|
|
109
139
|
indexBuffer,
|
|
110
140
|
indexCount: indices.length,
|
|
141
|
+
vao,
|
|
111
142
|
};
|
|
112
143
|
};
|
|
113
144
|
|
|
114
145
|
NiivueObject3D.getFirstPerpVector = function (v1) {
|
|
115
|
-
let v2 =
|
|
146
|
+
let v2 = vec3.fromValues(0.0, 0.0, 0.0);
|
|
116
147
|
if (v1[0] === 0.0) v2[0] = 1.0;
|
|
117
148
|
else if (v1[1] === 0.0) v2[1] = 1.0;
|
|
118
149
|
else if (v1[2] === 0.0) v2[2] = 1.0;
|
|
@@ -122,37 +153,175 @@ NiivueObject3D.getFirstPerpVector = function (v1) {
|
|
|
122
153
|
v2[0] = v1[2]; //scalp = z*x
|
|
123
154
|
v2[1] = v1[2]; //scalp = z*(x+y)
|
|
124
155
|
v2[2] = -(v1[0] + v1[1]); //scalp = z*(x+y)-z*(x+y) = 0
|
|
125
|
-
|
|
156
|
+
vec3.normalize(v2, v2);
|
|
126
157
|
}
|
|
127
158
|
return v2;
|
|
128
159
|
};
|
|
129
160
|
|
|
161
|
+
NiivueObject3D.subdivide = function (verts, faces) {
|
|
162
|
+
//Subdivide each triangle into four triangles, pushing verts to the unit sphere"""
|
|
163
|
+
let nv = verts.length / 3;
|
|
164
|
+
let nf = faces.length / 3;
|
|
165
|
+
let n = nf;
|
|
166
|
+
let vNew = vec3.create();
|
|
167
|
+
let nNew = vec3.create();
|
|
168
|
+
for (let faceIndex = 0; faceIndex < n; faceIndex++) {
|
|
169
|
+
//setlength(verts, nv + 3);
|
|
170
|
+
let fx = faces[faceIndex * 3 + 0];
|
|
171
|
+
let fy = faces[faceIndex * 3 + 1];
|
|
172
|
+
let fz = faces[faceIndex * 3 + 2];
|
|
173
|
+
let vx = vec3.fromValues(
|
|
174
|
+
verts[fx * 3 + 0],
|
|
175
|
+
verts[fx * 3 + 1],
|
|
176
|
+
verts[fx * 3 + 2]
|
|
177
|
+
);
|
|
178
|
+
let vy = vec3.fromValues(
|
|
179
|
+
verts[fy * 3 + 0],
|
|
180
|
+
verts[fy * 3 + 1],
|
|
181
|
+
verts[fy * 3 + 2]
|
|
182
|
+
);
|
|
183
|
+
let vz = vec3.fromValues(
|
|
184
|
+
verts[fz * 3 + 0],
|
|
185
|
+
verts[fz * 3 + 1],
|
|
186
|
+
verts[fz * 3 + 2]
|
|
187
|
+
);
|
|
188
|
+
vec3.add(vNew, vx, vy);
|
|
189
|
+
vec3.normalize(nNew, vNew);
|
|
190
|
+
verts.push(...nNew);
|
|
191
|
+
|
|
192
|
+
vec3.add(vNew, vy, vz);
|
|
193
|
+
vec3.normalize(nNew, vNew);
|
|
194
|
+
verts.push(...nNew);
|
|
195
|
+
|
|
196
|
+
vec3.add(vNew, vx, vz);
|
|
197
|
+
vec3.normalize(nNew, vNew);
|
|
198
|
+
verts.push(...nNew);
|
|
199
|
+
//Split the current triangle into four smaller triangles:
|
|
200
|
+
let face = [nv, nv + 1, nv + 2];
|
|
201
|
+
faces.push(...face);
|
|
202
|
+
face = [fx, nv, nv + 2];
|
|
203
|
+
faces.push(...face);
|
|
204
|
+
face = [nv, fy, nv + 1];
|
|
205
|
+
faces.push(...face);
|
|
206
|
+
faces[faceIndex * 3 + 0] = nv + 2;
|
|
207
|
+
faces[faceIndex * 3 + 1] = nv + 1;
|
|
208
|
+
faces[faceIndex * 3 + 2] = fz;
|
|
209
|
+
nf = nf + 3;
|
|
210
|
+
nv = nv + 3;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
NiivueObject3D.weldVertices = function (verts, faces) {
|
|
215
|
+
//unify identical vertices
|
|
216
|
+
let nv = verts.length / 3;
|
|
217
|
+
//yikes: bubble sort! TO DO: see Surfice for more efficient solution
|
|
218
|
+
let nUnique = 0; //first vertex is unique
|
|
219
|
+
//var remap = new Array();
|
|
220
|
+
let remap = new Int32Array(nv);
|
|
221
|
+
for (let i = 0; i < nv - 1; i++) {
|
|
222
|
+
if (remap[i] !== 0) continue; //previously tested
|
|
223
|
+
remap[i] = nUnique;
|
|
224
|
+
let v = i * 3;
|
|
225
|
+
let x = verts[v];
|
|
226
|
+
let y = verts[v + 1];
|
|
227
|
+
let z = verts[v + 2];
|
|
228
|
+
for (let j = i + 1; j < nv; j++) {
|
|
229
|
+
v += 3;
|
|
230
|
+
if (x === verts[v] && y === verts[v + 1] && z === verts[v + 2])
|
|
231
|
+
remap[j] = nUnique;
|
|
232
|
+
}
|
|
233
|
+
nUnique++; //another new vertex
|
|
234
|
+
} //for i
|
|
235
|
+
if (nUnique === nv) return verts;
|
|
236
|
+
//console.log('welding vertices removed redundant positions ', nv, '->', nUnique);
|
|
237
|
+
let nf = faces.length;
|
|
238
|
+
for (let f = 0; f < nf; f++) faces[f] = remap[faces[f]];
|
|
239
|
+
let vtx = verts.slice(0, nUnique * 3 - 1);
|
|
240
|
+
for (let i = 0; i < nv - 1; i++) {
|
|
241
|
+
let v = i * 3;
|
|
242
|
+
let r = remap[i] * 3;
|
|
243
|
+
vtx[r] = verts[v];
|
|
244
|
+
vtx[r + 1] = verts[v + 1];
|
|
245
|
+
vtx[r + 2] = verts[v + 2];
|
|
246
|
+
}
|
|
247
|
+
return vtx;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
NiivueObject3D.makeSphere = function (
|
|
251
|
+
vertices,
|
|
252
|
+
indices,
|
|
253
|
+
radius,
|
|
254
|
+
origin = [0, 0, 0]
|
|
255
|
+
) {
|
|
256
|
+
let vtx = [];
|
|
257
|
+
let idx = [];
|
|
258
|
+
if (this.sphereVtx !== undefined) {
|
|
259
|
+
//only generate unit sphere once...
|
|
260
|
+
vtx = this.sphereVtx.slice();
|
|
261
|
+
idx = this.sphereIdx.slice();
|
|
262
|
+
} else {
|
|
263
|
+
vtx = [
|
|
264
|
+
0.0, 0.0, 1.0, 0.894, 0.0, 0.447, 0.276, 0.851, 0.447, -0.724, 0.526,
|
|
265
|
+
0.447, -0.724, -0.526, 0.447, 0.276, -0.851, 0.447, 0.724, 0.526, -0.447,
|
|
266
|
+
-0.276, 0.851, -0.447, -0.894, 0.0, -0.447, -0.276, -0.851, -0.447, 0.724,
|
|
267
|
+
-0.526, -0.447, 0.0, 0.0, -1.0,
|
|
268
|
+
];
|
|
269
|
+
//let idx = new Uint16Array([
|
|
270
|
+
idx = [
|
|
271
|
+
0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 1, 7, 6, 11, 8, 7, 11, 9, 8, 11,
|
|
272
|
+
10, 9, 11, 6, 10, 11, 6, 2, 1, 7, 3, 2, 8, 4, 3, 9, 5, 4, 10, 1, 5, 6, 7,
|
|
273
|
+
2, 7, 8, 3, 8, 9, 4, 9, 10, 5, 10, 6, 1,
|
|
274
|
+
];
|
|
275
|
+
this.subdivide(vtx, idx);
|
|
276
|
+
this.subdivide(vtx, idx);
|
|
277
|
+
vtx = this.weldVertices(vtx, idx);
|
|
278
|
+
this.sphereVtx = vtx.slice();
|
|
279
|
+
this.sphereIdx = idx.slice();
|
|
280
|
+
}
|
|
281
|
+
for (let i = 0; i < vtx.length; i++) vtx[i] = vtx[i] * radius;
|
|
282
|
+
let nvtx = vtx.length / 3;
|
|
283
|
+
let j = 0;
|
|
284
|
+
for (let i = 0; i < nvtx; i++) {
|
|
285
|
+
vtx[j] = vtx[j] + origin[0];
|
|
286
|
+
j++;
|
|
287
|
+
vtx[j] = vtx[j] + origin[1];
|
|
288
|
+
j++;
|
|
289
|
+
vtx[j] = vtx[j] + origin[2];
|
|
290
|
+
j++;
|
|
291
|
+
}
|
|
292
|
+
let idx0 = Math.floor(vertices.length / 3); //first new vertex will be AFTER previous vertices
|
|
293
|
+
for (let i = 0; i < idx.length; i++) idx[i] = idx[i] + idx0;
|
|
294
|
+
|
|
295
|
+
indices.push(...idx);
|
|
296
|
+
vertices.push(...vtx);
|
|
297
|
+
};
|
|
298
|
+
|
|
130
299
|
NiivueObject3D.makeCylinder = function (
|
|
131
300
|
vertices,
|
|
132
301
|
indices,
|
|
133
302
|
start,
|
|
134
303
|
dest,
|
|
135
304
|
radius,
|
|
136
|
-
sides = 20
|
|
305
|
+
sides = 20,
|
|
306
|
+
endcaps = true
|
|
137
307
|
) {
|
|
138
308
|
if (sides < 3) sides = 3; //prism is minimal 3D cylinder
|
|
139
|
-
let v1 =
|
|
140
|
-
|
|
141
|
-
|
|
309
|
+
let v1 = vec3.create();
|
|
310
|
+
vec3.subtract(v1, dest, start);
|
|
311
|
+
vec3.normalize(v1, v1); //principle axis of cylinder
|
|
142
312
|
let v2 = NiivueObject3D.getFirstPerpVector(v1); //a unit length vector orthogonal to v1
|
|
143
313
|
// Get the second perp vector by cross product
|
|
144
|
-
let v3 =
|
|
145
|
-
|
|
146
|
-
|
|
314
|
+
let v3 = vec3.create();
|
|
315
|
+
vec3.cross(v3, v1, v2); //a unit length vector orthogonal to v1 and v2
|
|
316
|
+
vec3.normalize(v3, v3);
|
|
147
317
|
let num_v = 2 * sides;
|
|
148
318
|
let num_f = 2 * sides;
|
|
149
|
-
let endcaps = true;
|
|
150
319
|
if (endcaps) {
|
|
151
320
|
num_f += 2 * sides;
|
|
152
321
|
num_v += 2;
|
|
153
322
|
}
|
|
154
323
|
let idx0 = Math.floor(vertices.length / 3); //first new vertex will be AFTER previous vertices
|
|
155
|
-
let idx = new
|
|
324
|
+
let idx = new Uint32Array(num_f * 3);
|
|
156
325
|
let vtx = new Float32Array(num_v * 3);
|
|
157
326
|
function setV(i, vec3) {
|
|
158
327
|
vtx[i * 3 + 0] = vec3[0];
|
|
@@ -170,17 +339,17 @@ NiivueObject3D.makeCylinder = function (
|
|
|
170
339
|
setV(startPole, start);
|
|
171
340
|
setV(destPole, dest);
|
|
172
341
|
}
|
|
173
|
-
let pt1 =
|
|
174
|
-
let pt2 =
|
|
342
|
+
let pt1 = vec3.create();
|
|
343
|
+
let pt2 = vec3.create();
|
|
175
344
|
for (let i = 0; i < sides; i++) {
|
|
176
345
|
let c = Math.cos((i / sides) * 2 * Math.PI);
|
|
177
346
|
let s = Math.sin((i / sides) * 2 * Math.PI);
|
|
178
347
|
pt1[0] = radius * (c * v2[0] + s * v3[0]);
|
|
179
348
|
pt1[1] = radius * (c * v2[1] + s * v3[1]);
|
|
180
349
|
pt1[2] = radius * (c * v2[2] + s * v3[2]);
|
|
181
|
-
|
|
350
|
+
vec3.add(pt2, start, pt1);
|
|
182
351
|
setV(i, pt2);
|
|
183
|
-
|
|
352
|
+
vec3.add(pt2, dest, pt1);
|
|
184
353
|
setV(i + sides, pt2);
|
|
185
354
|
let nxt = 0;
|
|
186
355
|
if (i < sides - 1) nxt = i + 1;
|
|
@@ -194,3 +363,48 @@ NiivueObject3D.makeCylinder = function (
|
|
|
194
363
|
indices.push(...idx);
|
|
195
364
|
vertices.push(...vtx);
|
|
196
365
|
};
|
|
366
|
+
|
|
367
|
+
NiivueObject3D.makeColoredCylinder = function (
|
|
368
|
+
vertices,
|
|
369
|
+
indices,
|
|
370
|
+
colors,
|
|
371
|
+
start,
|
|
372
|
+
dest,
|
|
373
|
+
radius,
|
|
374
|
+
rgba255 = [192, 0, 0, 255],
|
|
375
|
+
sides = 20,
|
|
376
|
+
endcaps = false
|
|
377
|
+
) {
|
|
378
|
+
let nv = vertices.length / 3;
|
|
379
|
+
this.makeCylinder(vertices, indices, start, dest, radius, sides, endcaps);
|
|
380
|
+
nv = vertices.length / 3 - nv;
|
|
381
|
+
let clrs = [];
|
|
382
|
+
for (let i = 0; i < nv * 4 - 1; i += 4) {
|
|
383
|
+
clrs[i] = rgba255[0];
|
|
384
|
+
clrs[i + 1] = rgba255[1];
|
|
385
|
+
clrs[i + 2] = rgba255[2];
|
|
386
|
+
clrs[i + 3] = rgba255[3];
|
|
387
|
+
}
|
|
388
|
+
colors.push(...clrs);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
NiivueObject3D.makeColoredSphere = function (
|
|
392
|
+
vertices,
|
|
393
|
+
indices,
|
|
394
|
+
colors,
|
|
395
|
+
radius,
|
|
396
|
+
origin = [0, 0, 0],
|
|
397
|
+
rgba255 = [0, 0, 192, 255]
|
|
398
|
+
) {
|
|
399
|
+
let nv = vertices.length / 3;
|
|
400
|
+
this.makeSphere(vertices, indices, radius, origin);
|
|
401
|
+
nv = vertices.length / 3 - nv;
|
|
402
|
+
let clrs = [];
|
|
403
|
+
for (let i = 0; i < nv * 4 - 1; i += 4) {
|
|
404
|
+
clrs[i] = rgba255[0];
|
|
405
|
+
clrs[i + 1] = rgba255[1];
|
|
406
|
+
clrs[i + 2] = rgba255[2];
|
|
407
|
+
clrs[i + 3] = rgba255[3];
|
|
408
|
+
}
|
|
409
|
+
colors.push(...clrs);
|
|
410
|
+
};
|