zincjs 2.4.1-beta.7 → 3.0.1
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 +27 -22
- package/build/zinc.js +2 -2
- package/build/zinc.js.map +1 -1
- package/package.json +6 -2
- package/src/controls.js +1332 -1241
- package/src/geometryCSG.js +111 -115
- package/src/glyphsetCSG.js +51 -55
- package/src/loaders/GLTFToZincJSLoader.js +31 -33
- package/src/loaders/JSONLoader.js +339 -449
- package/src/loaders/OBJLoader.js +654 -851
- package/src/loaders/STLLoader.js +271 -329
- package/src/loaders/niftiReader.js +90 -59
- package/src/loaders/primitivesLoader.js +55 -52
- package/src/minimap.js +63 -43
- package/src/primitives/geometry.js +40 -44
- package/src/primitives/glyph.js +16 -19
- package/src/primitives/glyphset.js +229 -185
- package/src/primitives/label.js +29 -31
- package/src/primitives/lines.js +20 -20
- package/src/primitives/lines2.js +33 -39
- package/src/primitives/lod.js +43 -43
- package/src/primitives/marker.js +31 -32
- package/src/primitives/markerCluster.js +32 -35
- package/src/primitives/pointset.js +86 -83
- package/src/primitives/texturePrimitive.js +9 -10
- package/src/primitives/textureSlides.js +84 -97
- package/src/primitives/textureVolume.js +46 -49
- package/src/primitives/tubeLines.js +108 -108
- package/src/primitives/zincObject.js +176 -184
- package/src/region.js +145 -155
- package/src/renderRequests.js +3 -3
- package/src/renderer.js +635 -620
- package/src/scene.js +479 -419
- package/src/sceneExporter.js +22 -17
- package/src/sceneLoader.js +542 -296
- package/src/shaders/rgbVolumeRender.js +11 -18
- package/src/shaders/textureArray.js +5 -12
- package/src/shaders/textureSlide.js +10 -17
- package/src/shaders/volumeRender.js +11 -18
- package/src/shaders/volumeRender_old.js +11 -18
- package/src/shaders/volumeTexture.js +7 -14
- package/src/textSprite.js +23 -19
- package/src/texture/texture.js +14 -15
- package/src/texture/textureArray.js +14 -16
- package/src/three/InstancedPoints.js +2 -9
- package/src/three/Loader.js +334 -315
- package/src/three/line/Line.js +165 -215
- package/src/three/line/LineSegments.js +40 -55
- package/src/three/line/LineSegments2.js +322 -366
- package/src/three/line/LineSegmentsGeometry.js +239 -280
- package/src/three-js-csg.js +260 -252
- package/src/tsl/glyphRenderMaterial.js +12 -3
- package/src/tsl/glyphTransform.js +51 -29
- package/src/tsl/textureSlides.js +23 -24
- package/src/utilities.js +309 -371
- package/src/videoHandler.js +76 -83
- package/src/workers/geometryCSG.worker.js +33 -36
- package/src/workers/geometryCSGInternal.js +39 -44
- package/src/zinc.js +4 -7
- package/vite.config.js +7 -7
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
Box3,
|
|
3
|
+
InstancedInterleavedBuffer,
|
|
4
|
+
InterleavedBufferAttribute,
|
|
5
|
+
Line3,
|
|
6
|
+
MathUtils,
|
|
7
|
+
Matrix4,
|
|
8
|
+
Mesh,
|
|
9
|
+
Sphere,
|
|
10
|
+
Vector3,
|
|
11
|
+
Vector4,
|
|
12
|
+
Line2NodeMaterial,
|
|
13
|
+
Vector2,
|
|
14
14
|
} from 'three/webgpu';
|
|
15
15
|
import { LineSegmentsGeometry } from './LineSegmentsGeometry.js';
|
|
16
16
|
|
|
@@ -35,193 +35,173 @@ let _ray, _lineWidth;
|
|
|
35
35
|
|
|
36
36
|
// Returns the margin required to expand by in world space given the distance from the camera,
|
|
37
37
|
// line width, resolution, and camera projection
|
|
38
|
-
function getWorldSpaceHalfWidth(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) );
|
|
51
|
-
|
|
38
|
+
function getWorldSpaceHalfWidth(camera, distance, resolution) {
|
|
39
|
+
// transform into clip space, adjust the x and y values by the pixel width offset, then
|
|
40
|
+
// transform back into world space to get world offset. Note clip space is [-1, 1] so full
|
|
41
|
+
// width does not need to be halved.
|
|
42
|
+
_clipToWorldVector.set(0, 0, -distance, 1.0).applyMatrix4(camera.projectionMatrix);
|
|
43
|
+
_clipToWorldVector.multiplyScalar(1.0 / _clipToWorldVector.w);
|
|
44
|
+
_clipToWorldVector.x = _lineWidth / resolution.width;
|
|
45
|
+
_clipToWorldVector.y = _lineWidth / resolution.height;
|
|
46
|
+
_clipToWorldVector.applyMatrix4(camera.projectionMatrixInverse);
|
|
47
|
+
_clipToWorldVector.multiplyScalar(1.0 / _clipToWorldVector.w);
|
|
48
|
+
|
|
49
|
+
return Math.abs(Math.max(_clipToWorldVector.x, _clipToWorldVector.y));
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
function raycastWorldUnits(
|
|
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
|
-
|
|
52
|
+
function raycastWorldUnits(lineSegments, intersects) {
|
|
53
|
+
const matrixWorld = lineSegments.matrixWorld;
|
|
54
|
+
const geometry = lineSegments.geometry;
|
|
55
|
+
const instanceStart = geometry.attributes.instanceStart;
|
|
56
|
+
const instanceEnd = geometry.attributes.instanceEnd;
|
|
57
|
+
const segmentCount = Math.min(geometry.instanceCount, instanceStart.count);
|
|
58
|
+
|
|
59
|
+
for (let i = 0, l = segmentCount; i < l; i++) {
|
|
60
|
+
_line.start.fromBufferAttribute(instanceStart, i);
|
|
61
|
+
_line.end.fromBufferAttribute(instanceEnd, i);
|
|
62
|
+
|
|
63
|
+
_line.applyMatrix4(matrixWorld);
|
|
64
|
+
|
|
65
|
+
const pointOnLine = new Vector3();
|
|
66
|
+
const point = new Vector3();
|
|
67
|
+
|
|
68
|
+
_ray.distanceSqToSegment(_line.start, _line.end, point, pointOnLine);
|
|
69
|
+
const isInside = point.distanceTo(pointOnLine) < _lineWidth * 0.5;
|
|
70
|
+
|
|
71
|
+
if (isInside) {
|
|
72
|
+
intersects.push({
|
|
73
|
+
point,
|
|
74
|
+
pointOnLine,
|
|
75
|
+
distance: _ray.origin.distanceTo(point),
|
|
76
|
+
object: lineSegments,
|
|
77
|
+
face: null,
|
|
78
|
+
faceIndex: i,
|
|
79
|
+
uv: null,
|
|
80
|
+
uv1: null,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
92
84
|
}
|
|
93
85
|
|
|
94
|
-
function raycastScreenSpace(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const matrixWorld = lineSegments.matrixWorld;
|
|
98
|
-
|
|
99
|
-
const resolution = lineSegments._resolution;
|
|
100
|
-
|
|
101
|
-
const geometry = lineSegments.geometry;
|
|
102
|
-
const instanceStart = geometry.attributes.instanceStart;
|
|
103
|
-
const instanceEnd = geometry.attributes.instanceEnd;
|
|
104
|
-
const segmentCount = Math.min( geometry.instanceCount, instanceStart.count );
|
|
105
|
-
|
|
106
|
-
const near = - camera.near;
|
|
107
|
-
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
// pick a point 1 unit out along the ray to avoid the ray origin
|
|
111
|
-
// sitting at the camera origin which will cause "w" to be 0 when
|
|
112
|
-
// applying the projection matrix.
|
|
113
|
-
_ray.at( 1, _ssOrigin );
|
|
114
|
-
|
|
115
|
-
// ndc space [ - 1.0, 1.0 ]
|
|
116
|
-
_ssOrigin.w = 1;
|
|
117
|
-
_ssOrigin.applyMatrix4( camera.matrixWorldInverse );
|
|
118
|
-
_ssOrigin.applyMatrix4( projectionMatrix );
|
|
119
|
-
_ssOrigin.multiplyScalar( 1 / _ssOrigin.w );
|
|
120
|
-
|
|
121
|
-
// screen space
|
|
122
|
-
_ssOrigin.x *= resolution.x / 2;
|
|
123
|
-
_ssOrigin.y *= resolution.y / 2;
|
|
124
|
-
_ssOrigin.z = 0;
|
|
125
|
-
|
|
126
|
-
_ssOrigin3.copy( _ssOrigin );
|
|
127
|
-
|
|
128
|
-
_mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
|
|
129
|
-
|
|
130
|
-
for ( let i = 0, l = segmentCount; i < l; i ++ ) {
|
|
131
|
-
|
|
132
|
-
_start4.fromBufferAttribute( instanceStart, i );
|
|
133
|
-
_end4.fromBufferAttribute( instanceEnd, i );
|
|
134
|
-
|
|
135
|
-
_start4.w = 1;
|
|
136
|
-
_end4.w = 1;
|
|
137
|
-
|
|
138
|
-
// camera space
|
|
139
|
-
_start4.applyMatrix4( _mvMatrix );
|
|
140
|
-
_end4.applyMatrix4( _mvMatrix );
|
|
141
|
-
|
|
142
|
-
// skip the segment if it's entirely behind the camera
|
|
143
|
-
const isBehindCameraNear = _start4.z > near && _end4.z > near;
|
|
144
|
-
if ( isBehindCameraNear ) {
|
|
86
|
+
function raycastScreenSpace(lineSegments, camera, intersects) {
|
|
87
|
+
const projectionMatrix = camera.projectionMatrix;
|
|
88
|
+
const matrixWorld = lineSegments.matrixWorld;
|
|
145
89
|
|
|
146
|
-
|
|
90
|
+
const resolution = lineSegments._resolution;
|
|
147
91
|
|
|
148
|
-
|
|
92
|
+
const geometry = lineSegments.geometry;
|
|
93
|
+
const instanceStart = geometry.attributes.instanceStart;
|
|
94
|
+
const instanceEnd = geometry.attributes.instanceEnd;
|
|
95
|
+
const segmentCount = Math.min(geometry.instanceCount, instanceStart.count);
|
|
149
96
|
|
|
150
|
-
|
|
151
|
-
if ( _start4.z > near ) {
|
|
97
|
+
const near = -camera.near;
|
|
152
98
|
|
|
153
|
-
|
|
154
|
-
const t = ( _start4.z - near ) / deltaDist;
|
|
155
|
-
_start4.lerp( _end4, t );
|
|
156
|
-
|
|
157
|
-
} else if ( _end4.z > near ) {
|
|
158
|
-
|
|
159
|
-
const deltaDist = _end4.z - _start4.z;
|
|
160
|
-
const t = ( _end4.z - near ) / deltaDist;
|
|
161
|
-
_end4.lerp( _start4, t );
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// clip space
|
|
166
|
-
_start4.applyMatrix4( projectionMatrix );
|
|
167
|
-
_end4.applyMatrix4( projectionMatrix );
|
|
168
|
-
|
|
169
|
-
// ndc space [ - 1.0, 1.0 ]
|
|
170
|
-
_start4.multiplyScalar( 1 / _start4.w );
|
|
171
|
-
_end4.multiplyScalar( 1 / _end4.w );
|
|
172
|
-
|
|
173
|
-
// screen space
|
|
174
|
-
_start4.x *= resolution.x / 2;
|
|
175
|
-
_start4.y *= resolution.y / 2;
|
|
176
|
-
|
|
177
|
-
_end4.x *= resolution.x / 2;
|
|
178
|
-
_end4.y *= resolution.y / 2;
|
|
179
|
-
|
|
180
|
-
// create 2d segment
|
|
181
|
-
_line.start.copy( _start4 );
|
|
182
|
-
_line.start.z = 0;
|
|
183
|
-
|
|
184
|
-
_line.end.copy( _end4 );
|
|
185
|
-
_line.end.z = 0;
|
|
186
|
-
|
|
187
|
-
// get closest point on ray to segment
|
|
188
|
-
const param = _line.closestPointToPointParameter( _ssOrigin3, true );
|
|
189
|
-
_line.at( param, _closestPoint );
|
|
190
|
-
|
|
191
|
-
// check if the intersection point is within clip space
|
|
192
|
-
const zPos = MathUtils.lerp( _start4.z, _end4.z, param );
|
|
193
|
-
const isInClipSpace = zPos >= - 1 && zPos <= 1;
|
|
194
|
-
|
|
195
|
-
const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5;
|
|
196
|
-
|
|
197
|
-
if ( isInClipSpace && isInside ) {
|
|
198
|
-
|
|
199
|
-
_line.start.fromBufferAttribute( instanceStart, i );
|
|
200
|
-
_line.end.fromBufferAttribute( instanceEnd, i );
|
|
201
|
-
|
|
202
|
-
_line.start.applyMatrix4( matrixWorld );
|
|
203
|
-
_line.end.applyMatrix4( matrixWorld );
|
|
204
|
-
|
|
205
|
-
const pointOnLine = new Vector3();
|
|
206
|
-
const point = new Vector3();
|
|
207
|
-
|
|
208
|
-
_ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine );
|
|
209
|
-
|
|
210
|
-
intersects.push( {
|
|
211
|
-
point: point,
|
|
212
|
-
pointOnLine: pointOnLine,
|
|
213
|
-
distance: _ray.origin.distanceTo( point ),
|
|
214
|
-
object: lineSegments,
|
|
215
|
-
face: null,
|
|
216
|
-
faceIndex: i,
|
|
217
|
-
uv: null,
|
|
218
|
-
uv1: null,
|
|
219
|
-
} );
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
}
|
|
99
|
+
//
|
|
224
100
|
|
|
101
|
+
// pick a point 1 unit out along the ray to avoid the ray origin
|
|
102
|
+
// sitting at the camera origin which will cause "w" to be 0 when
|
|
103
|
+
// applying the projection matrix.
|
|
104
|
+
_ray.at(1, _ssOrigin);
|
|
105
|
+
|
|
106
|
+
// ndc space [ - 1.0, 1.0 ]
|
|
107
|
+
_ssOrigin.w = 1;
|
|
108
|
+
_ssOrigin.applyMatrix4(camera.matrixWorldInverse);
|
|
109
|
+
_ssOrigin.applyMatrix4(projectionMatrix);
|
|
110
|
+
_ssOrigin.multiplyScalar(1 / _ssOrigin.w);
|
|
111
|
+
|
|
112
|
+
// screen space
|
|
113
|
+
_ssOrigin.x *= resolution.x / 2;
|
|
114
|
+
_ssOrigin.y *= resolution.y / 2;
|
|
115
|
+
_ssOrigin.z = 0;
|
|
116
|
+
|
|
117
|
+
_ssOrigin3.copy(_ssOrigin);
|
|
118
|
+
|
|
119
|
+
_mvMatrix.multiplyMatrices(camera.matrixWorldInverse, matrixWorld);
|
|
120
|
+
|
|
121
|
+
for (let i = 0, l = segmentCount; i < l; i++) {
|
|
122
|
+
_start4.fromBufferAttribute(instanceStart, i);
|
|
123
|
+
_end4.fromBufferAttribute(instanceEnd, i);
|
|
124
|
+
|
|
125
|
+
_start4.w = 1;
|
|
126
|
+
_end4.w = 1;
|
|
127
|
+
|
|
128
|
+
// camera space
|
|
129
|
+
_start4.applyMatrix4(_mvMatrix);
|
|
130
|
+
_end4.applyMatrix4(_mvMatrix);
|
|
131
|
+
|
|
132
|
+
// skip the segment if it's entirely behind the camera
|
|
133
|
+
const isBehindCameraNear = _start4.z > near && _end4.z > near;
|
|
134
|
+
if (isBehindCameraNear) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// trim the segment if it extends behind camera near
|
|
139
|
+
if (_start4.z > near) {
|
|
140
|
+
const deltaDist = _start4.z - _end4.z;
|
|
141
|
+
const t = (_start4.z - near) / deltaDist;
|
|
142
|
+
_start4.lerp(_end4, t);
|
|
143
|
+
} else if (_end4.z > near) {
|
|
144
|
+
const deltaDist = _end4.z - _start4.z;
|
|
145
|
+
const t = (_end4.z - near) / deltaDist;
|
|
146
|
+
_end4.lerp(_start4, t);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// clip space
|
|
150
|
+
_start4.applyMatrix4(projectionMatrix);
|
|
151
|
+
_end4.applyMatrix4(projectionMatrix);
|
|
152
|
+
|
|
153
|
+
// ndc space [ - 1.0, 1.0 ]
|
|
154
|
+
_start4.multiplyScalar(1 / _start4.w);
|
|
155
|
+
_end4.multiplyScalar(1 / _end4.w);
|
|
156
|
+
|
|
157
|
+
// screen space
|
|
158
|
+
_start4.x *= resolution.x / 2;
|
|
159
|
+
_start4.y *= resolution.y / 2;
|
|
160
|
+
|
|
161
|
+
_end4.x *= resolution.x / 2;
|
|
162
|
+
_end4.y *= resolution.y / 2;
|
|
163
|
+
|
|
164
|
+
// create 2d segment
|
|
165
|
+
_line.start.copy(_start4);
|
|
166
|
+
_line.start.z = 0;
|
|
167
|
+
|
|
168
|
+
_line.end.copy(_end4);
|
|
169
|
+
_line.end.z = 0;
|
|
170
|
+
|
|
171
|
+
// get closest point on ray to segment
|
|
172
|
+
const param = _line.closestPointToPointParameter(_ssOrigin3, true);
|
|
173
|
+
_line.at(param, _closestPoint);
|
|
174
|
+
|
|
175
|
+
// check if the intersection point is within clip space
|
|
176
|
+
const zPos = MathUtils.lerp(_start4.z, _end4.z, param);
|
|
177
|
+
const isInClipSpace = zPos >= -1 && zPos <= 1;
|
|
178
|
+
|
|
179
|
+
const isInside = _ssOrigin3.distanceTo(_closestPoint) < _lineWidth * 0.5;
|
|
180
|
+
|
|
181
|
+
if (isInClipSpace && isInside) {
|
|
182
|
+
_line.start.fromBufferAttribute(instanceStart, i);
|
|
183
|
+
_line.end.fromBufferAttribute(instanceEnd, i);
|
|
184
|
+
|
|
185
|
+
_line.start.applyMatrix4(matrixWorld);
|
|
186
|
+
_line.end.applyMatrix4(matrixWorld);
|
|
187
|
+
|
|
188
|
+
const pointOnLine = new Vector3();
|
|
189
|
+
const point = new Vector3();
|
|
190
|
+
|
|
191
|
+
_ray.distanceSqToSegment(_line.start, _line.end, point, pointOnLine);
|
|
192
|
+
|
|
193
|
+
intersects.push({
|
|
194
|
+
point: point,
|
|
195
|
+
pointOnLine: pointOnLine,
|
|
196
|
+
distance: _ray.origin.distanceTo(point),
|
|
197
|
+
object: lineSegments,
|
|
198
|
+
face: null,
|
|
199
|
+
faceIndex: i,
|
|
200
|
+
uv: null,
|
|
201
|
+
uv1: null,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
225
205
|
}
|
|
226
206
|
|
|
227
207
|
/**
|
|
@@ -238,182 +218,158 @@ function raycastScreenSpace( lineSegments, camera, intersects ) {
|
|
|
238
218
|
* @three_import import { LineSegments2 } from 'three/addons/lines/webgpu/LineSegments2.js';
|
|
239
219
|
*/
|
|
240
220
|
class LineSegments2 extends Mesh {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, this._resolution );
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
_box.expandByScalar( boxMargin );
|
|
398
|
-
|
|
399
|
-
if ( _ray.intersectsBox( _box ) === false ) {
|
|
400
|
-
|
|
401
|
-
return;
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if ( worldUnits ) {
|
|
406
|
-
|
|
407
|
-
raycastWorldUnits( this, intersects );
|
|
408
|
-
|
|
409
|
-
} else {
|
|
410
|
-
|
|
411
|
-
raycastScreenSpace( this, camera, intersects );
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Constructs a new wide line.
|
|
223
|
+
*
|
|
224
|
+
* @param {LineSegmentsGeometry} [geometry] - The line geometry.
|
|
225
|
+
* @param {Line2NodeMaterial} [material] - The line material.
|
|
226
|
+
*/
|
|
227
|
+
constructor(
|
|
228
|
+
geometry = new LineSegmentsGeometry(),
|
|
229
|
+
material = new Line2NodeMaterial({ color: Math.random() * 0xffffff }),
|
|
230
|
+
) {
|
|
231
|
+
super(geometry, material);
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* This flag can be used for type testing.
|
|
235
|
+
*
|
|
236
|
+
* @type {boolean}
|
|
237
|
+
* @readonly
|
|
238
|
+
* @default true
|
|
239
|
+
*/
|
|
240
|
+
this.isLineSegments2 = true;
|
|
241
|
+
|
|
242
|
+
this.type = 'LineSegments2';
|
|
243
|
+
|
|
244
|
+
this._resolution = new Vector2();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Computes an array of distance values which are necessary for rendering dashed lines.
|
|
249
|
+
* For each vertex in the geometry, the method calculates the cumulative length from the
|
|
250
|
+
* current point to the very beginning of the line.
|
|
251
|
+
*
|
|
252
|
+
* @return {LineSegments2} A reference to this instance.
|
|
253
|
+
*/
|
|
254
|
+
computeLineDistances() {
|
|
255
|
+
// for backwards-compatibility, but could be a method of LineSegmentsGeometry...
|
|
256
|
+
|
|
257
|
+
const geometry = this.geometry;
|
|
258
|
+
|
|
259
|
+
const instanceStart = geometry.attributes.instanceStart;
|
|
260
|
+
const instanceEnd = geometry.attributes.instanceEnd;
|
|
261
|
+
const lineDistances = new Float32Array(2 * instanceStart.count);
|
|
262
|
+
|
|
263
|
+
for (let i = 0, j = 0, l = instanceStart.count; i < l; i++, j += 2) {
|
|
264
|
+
_start.fromBufferAttribute(instanceStart, i);
|
|
265
|
+
_end.fromBufferAttribute(instanceEnd, i);
|
|
266
|
+
|
|
267
|
+
lineDistances[j] = j === 0 ? 0 : lineDistances[j - 1];
|
|
268
|
+
lineDistances[j + 1] = lineDistances[j] + _start.distanceTo(_end);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const instanceDistanceBuffer = new InstancedInterleavedBuffer(lineDistances, 2, 1); // d0, d1
|
|
272
|
+
|
|
273
|
+
geometry.setAttribute(
|
|
274
|
+
'instanceDistanceStart',
|
|
275
|
+
new InterleavedBufferAttribute(instanceDistanceBuffer, 1, 0),
|
|
276
|
+
); // d0
|
|
277
|
+
geometry.setAttribute(
|
|
278
|
+
'instanceDistanceEnd',
|
|
279
|
+
new InterleavedBufferAttribute(instanceDistanceBuffer, 1, 1),
|
|
280
|
+
); // d1
|
|
281
|
+
|
|
282
|
+
return this;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
onBeforeRender(renderer) {
|
|
286
|
+
renderer.getViewport(_viewport);
|
|
287
|
+
this._resolution.set(_viewport.z, _viewport.w);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Computes intersection points between a casted ray and this instance.
|
|
292
|
+
*
|
|
293
|
+
* @param {Raycaster} raycaster - The raycaster.
|
|
294
|
+
* @param {Array<Object>} intersects - The target array that holds the intersection points.
|
|
295
|
+
*/
|
|
296
|
+
raycast(raycaster, intersects) {
|
|
297
|
+
const worldUnits = this.material.worldUnits;
|
|
298
|
+
const camera = raycaster.camera;
|
|
299
|
+
|
|
300
|
+
if (camera === null && !worldUnits) {
|
|
301
|
+
console.error(
|
|
302
|
+
'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.',
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// early out if no resolution has been set (line was not rendered yet)
|
|
307
|
+
|
|
308
|
+
if (worldUnits === false && (this._resolution.x === 0 || this._resolution.y === 0)) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const threshold =
|
|
313
|
+
raycaster.params.Line2 !== undefined ? raycaster.params.Line2.threshold || 0 : 0;
|
|
314
|
+
|
|
315
|
+
_ray = raycaster.ray;
|
|
316
|
+
|
|
317
|
+
const matrixWorld = this.matrixWorld;
|
|
318
|
+
const geometry = this.geometry;
|
|
319
|
+
const material = this.material;
|
|
320
|
+
|
|
321
|
+
_lineWidth = material.linewidth + threshold;
|
|
322
|
+
|
|
323
|
+
// check if we intersect the sphere bounds
|
|
324
|
+
if (geometry.boundingSphere === null) {
|
|
325
|
+
geometry.computeBoundingSphere();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
_sphere.copy(geometry.boundingSphere).applyMatrix4(matrixWorld);
|
|
329
|
+
|
|
330
|
+
// increase the sphere bounds by the worst case line screen space width
|
|
331
|
+
let sphereMargin;
|
|
332
|
+
if (worldUnits) {
|
|
333
|
+
sphereMargin = _lineWidth * 0.5;
|
|
334
|
+
} else {
|
|
335
|
+
const distanceToSphere = Math.max(camera.near, _sphere.distanceToPoint(_ray.origin));
|
|
336
|
+
sphereMargin = getWorldSpaceHalfWidth(camera, distanceToSphere, this._resolution);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
_sphere.radius += sphereMargin;
|
|
340
|
+
|
|
341
|
+
if (_ray.intersectsSphere(_sphere) === false) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// check if we intersect the box bounds
|
|
346
|
+
if (geometry.boundingBox === null) {
|
|
347
|
+
geometry.computeBoundingBox();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
_box.copy(geometry.boundingBox).applyMatrix4(matrixWorld);
|
|
351
|
+
|
|
352
|
+
// increase the box bounds by the worst case line width
|
|
353
|
+
let boxMargin;
|
|
354
|
+
if (worldUnits) {
|
|
355
|
+
boxMargin = _lineWidth * 0.5;
|
|
356
|
+
} else {
|
|
357
|
+
const distanceToBox = Math.max(camera.near, _box.distanceToPoint(_ray.origin));
|
|
358
|
+
boxMargin = getWorldSpaceHalfWidth(camera, distanceToBox, this._resolution);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
_box.expandByScalar(boxMargin);
|
|
362
|
+
|
|
363
|
+
if (_ray.intersectsBox(_box) === false) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (worldUnits) {
|
|
368
|
+
raycastWorldUnits(this, intersects);
|
|
369
|
+
} else {
|
|
370
|
+
raycastScreenSpace(this, camera, intersects);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
417
373
|
}
|
|
418
374
|
|
|
419
375
|
export { LineSegments2 };
|