zincjs 2.4.0 → 2.4.1-beta.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/build/zinc.js +3 -486
- package/build/zinc.js.map +1 -1
- package/package.json +3 -4
- package/src/controls.js +1 -1
- package/src/geometryCSG.js +1 -1
- package/src/glyphsetCSG.js +1 -1
- package/src/loaders/GLTFToZincJSLoader.js +1 -1
- package/src/loaders/JSONLoader.js +204 -377
- package/src/loaders/OBJLoader.js +1 -1
- package/src/loaders/STLLoader.js +1 -1
- package/src/loaders/niftiReader.js +6 -4
- package/src/loaders/primitivesLoader.js +7 -9
- package/src/minimap.js +1 -1
- package/src/primitives/geometry.js +11 -29
- package/src/primitives/glyph.js +1 -1
- package/src/primitives/glyphset.js +2 -4
- package/src/primitives/label.js +1 -1
- package/src/primitives/lines.js +12 -5
- package/src/primitives/lines2.js +4 -8
- package/src/primitives/lod.js +9 -3
- package/src/primitives/marker.js +1 -1
- package/src/primitives/markerCluster.js +1 -1
- package/src/primitives/pointset.js +368 -52
- package/src/primitives/textureSlides.js +59 -16
- package/src/primitives/textureVolume.js +1 -1
- package/src/primitives/tubeLines.js +20 -3
- package/src/primitives/zincObject.js +13 -1
- package/src/region.js +1 -1
- package/src/renderer.js +17 -13
- package/src/scene.js +20 -8
- package/src/sceneLoader.js +1 -1
- package/src/shaders/rgbVolumeRender.js +1 -1
- package/src/shaders/textureSlide.js +1 -1
- package/src/texture/texture.js +1 -1
- package/src/texture/textureArray.js +9 -2
- package/src/three/GLTFExporter.js +55 -2
- package/src/three/InstancedPoints.js +73 -0
- package/src/three/Loader.js +1 -1
- package/src/three/line/Line.js +1 -1
- package/src/three/line/LineSegments.js +1 -1
- package/src/three/line/LineSegments2.js +24 -39
- package/src/three/line/LineSegmentsGeometry.js +1 -1
- package/src/tls/morphColorMaterial.js +65 -0
- package/src/tls/pointsMaterial.js +79 -0
- package/src/tls/textureSlides.js +126 -0
- package/src/utilities.js +47 -70
- package/src/videoHandler.js +1 -2
- package/src/workers/geometryCSG.worker.js +1 -1
- package/src/workers/geometryCSGInternal.js +1 -1
- package/src/zinc.js +1 -1
- package/vite.config.js +3 -1
- package/src/primitives/augmentShader.js +0 -45
- package/src/three/Geometry.js +0 -2176
- package/src/three/Points.js +0 -224
- package/src/three/line/LineMaterial.js +0 -726
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as THREE from 'three';
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
2
|
import { mergeGeometries } from '../utilities';
|
|
3
3
|
import { ZincObject } from './zincObject';
|
|
4
4
|
|
|
@@ -31,7 +31,7 @@ const TubeLines = function () {
|
|
|
31
31
|
this.createLineSegment = (geometryIn, materialIn, options) => {
|
|
32
32
|
if (geometryIn && materialIn) {
|
|
33
33
|
dataIn = { geometryIn, materialIn, options };
|
|
34
|
-
const geometry = getTubeLinesGeometry(geometryIn
|
|
34
|
+
const geometry = getTubeLinesGeometry(extractVertices(geometryIn));
|
|
35
35
|
const material = new THREE.MeshStandardMaterial({ color: materialIn.color });
|
|
36
36
|
const mesh = new THREE.Mesh(geometry, material);
|
|
37
37
|
this.setMesh(mesh, options.localTimeEnabled, options.localMorphColour);
|
|
@@ -86,10 +86,27 @@ const TubeLines = function () {
|
|
|
86
86
|
mesh.geometry.dispose();
|
|
87
87
|
|
|
88
88
|
geometryConfig = Object.assign(geometryConfig, { radius, radialSegments });
|
|
89
|
-
mesh.geometry = getTubeLinesGeometry(geometryIn
|
|
89
|
+
mesh.geometry = getTubeLinesGeometry(extractVertices(geometryIn));
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Read the position attribute of a BufferGeometry into an array of
|
|
95
|
+
* THREE.Vector3, since TubeGeometry/CatmullRomCurve3/LineCurve3 need
|
|
96
|
+
* actual Vector3 instances to work with, not a flat typed array.
|
|
97
|
+
*
|
|
98
|
+
* @param {THREE.BufferGeometry} geometry
|
|
99
|
+
* @returns {Array}
|
|
100
|
+
*/
|
|
101
|
+
const extractVertices = (geometry) => {
|
|
102
|
+
const position = geometry.getAttribute('position');
|
|
103
|
+
const vertices = [];
|
|
104
|
+
for (let i = 0; i < position.count; i++) {
|
|
105
|
+
vertices.push(new THREE.Vector3().fromBufferAttribute(position, i));
|
|
106
|
+
}
|
|
107
|
+
return vertices;
|
|
108
|
+
}
|
|
109
|
+
|
|
93
110
|
/**
|
|
94
111
|
* Get merged geometry from list of geometry vertices
|
|
95
112
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as THREE from 'three';
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
2
|
import {
|
|
3
3
|
createBufferGeometry,
|
|
4
4
|
getBoundingBox,
|
|
@@ -183,6 +183,10 @@ ZincObject.prototype.setMesh = function(mesh, localTimeEnabled, localMorphColour
|
|
|
183
183
|
this.clipAction.loop = THREE.LoopRepeat;
|
|
184
184
|
this.clipAction.clampWhenFinished = true;
|
|
185
185
|
this.clipAction.play();
|
|
186
|
+
//Evaluate the clip immediately so morphTargetInfluences reflects
|
|
187
|
+
//time 0 right away, rather than staying at its all-zero default
|
|
188
|
+
//until the first mixer.update() from playback/setMorphTime.
|
|
189
|
+
this.mixer.update(0);
|
|
186
190
|
}
|
|
187
191
|
}
|
|
188
192
|
}
|
|
@@ -200,6 +204,14 @@ ZincObject.prototype.setMesh = function(mesh, localTimeEnabled, localMorphColour
|
|
|
200
204
|
geometry.setAttribute('morphTarget1', geometry.getAttribute( 'position' ) );
|
|
201
205
|
}
|
|
202
206
|
}
|
|
207
|
+
if (this.morphColour) {
|
|
208
|
+
//Make sure morphColor0/morphColor1 exist before this mesh is ever
|
|
209
|
+
//rendered. WebGPU builds its pipeline against whatever attributes the
|
|
210
|
+
//geometry has at first render, and adding these two afterwards doesn't
|
|
211
|
+
//get picked up by an already-built pipeline - the object would render
|
|
212
|
+
//black forever after, since the colour shader can no longer see them.
|
|
213
|
+
this.initiateMorphColor();
|
|
214
|
+
}
|
|
203
215
|
this.boundingBoxUpdateRequired = true;
|
|
204
216
|
}
|
|
205
217
|
|
package/src/region.js
CHANGED
package/src/renderer.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import * as THREE from 'three';
|
|
2
|
-
//import { WebGPURenderer } from 'three/webgpu';
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
3
2
|
import { ResizeSensor } from 'css-element-queries';
|
|
4
3
|
import { Scene } from './scene';
|
|
5
4
|
/**
|
|
@@ -77,8 +76,9 @@ const Renderer = function (containerIn) {
|
|
|
77
76
|
*/
|
|
78
77
|
this.onWindowResize = () => {
|
|
79
78
|
currentScene.onWindowResize();
|
|
80
|
-
|
|
81
|
-
const
|
|
79
|
+
//Give it a miniumum size of 1 x 1
|
|
80
|
+
const width = this.getDrawingWidth() || 1;
|
|
81
|
+
const height = this.getDrawingHeight() || 1;
|
|
82
82
|
if (renderer != undefined) {
|
|
83
83
|
let localRect = undefined;
|
|
84
84
|
if (container) {
|
|
@@ -109,7 +109,7 @@ const Renderer = function (containerIn) {
|
|
|
109
109
|
/**
|
|
110
110
|
* Initialise the renderer and its visualisations.
|
|
111
111
|
*/
|
|
112
|
-
this.initialiseVisualisation = parameters => {
|
|
112
|
+
this.initialiseVisualisation = async (parameters) => {
|
|
113
113
|
if (!isInitialised) {
|
|
114
114
|
parameters = parameters || {};
|
|
115
115
|
if (parameters['antialias'] === undefined) {
|
|
@@ -132,10 +132,10 @@ const Renderer = function (containerIn) {
|
|
|
132
132
|
canvas = parameters["canvas"];
|
|
133
133
|
}
|
|
134
134
|
//parameters["forceWebGL"] = true;
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
renderer = new THREE.WebGPURenderer(parameters);
|
|
136
|
+
await renderer.init();
|
|
137
137
|
|
|
138
|
-
renderer = new THREE.WebGLRenderer(parameters);
|
|
138
|
+
//renderer = new THREE.WebGLRenderer(parameters);
|
|
139
139
|
if (container !== undefined) {
|
|
140
140
|
container.appendChild( renderer.domElement );
|
|
141
141
|
}
|
|
@@ -208,10 +208,10 @@ const Renderer = function (containerIn) {
|
|
|
208
208
|
* @return {Zinc.Scene}
|
|
209
209
|
*/
|
|
210
210
|
this.getSceneByName = name => {
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
return sceneMap[name];
|
|
212
|
+
}
|
|
213
213
|
|
|
214
|
-
|
|
214
|
+
/*
|
|
215
215
|
* Create a new scene with the provided name if scene with the same name exists,
|
|
216
216
|
* return undefined.
|
|
217
217
|
*
|
|
@@ -244,6 +244,10 @@ const Renderer = function (containerIn) {
|
|
|
244
244
|
logoSprite.position.set(calculatedWidth, calculatedHeight, 1 );
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
+
return sceneMap[name];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
247
251
|
};
|
|
248
252
|
|
|
249
253
|
const updateOrthoCamera = () => {
|
|
@@ -573,11 +577,11 @@ const Renderer = function (containerIn) {
|
|
|
573
577
|
}
|
|
574
578
|
|
|
575
579
|
this.forceContextLoss = () => {
|
|
576
|
-
|
|
580
|
+
// renderer.forceContextLoss();
|
|
577
581
|
}
|
|
578
582
|
|
|
579
583
|
this.forceContextRestore= () => {
|
|
580
|
-
|
|
584
|
+
// renderer.forceContextRestore();
|
|
581
585
|
}
|
|
582
586
|
|
|
583
587
|
/**
|
package/src/scene.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import * as THREE from 'three';
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
2
|
import { CameraControls, StereoEffect } from './controls';
|
|
3
3
|
import { LineSegments } from './three/line/LineSegments';
|
|
4
4
|
import { MarkerCluster } from './primitives/markerCluster';
|
|
5
5
|
import { Minimap } from './minimap';
|
|
6
6
|
import { Region } from './region';
|
|
7
|
-
import {
|
|
7
|
+
import { InstancedPoints } from './three/InstancedPoints';
|
|
8
8
|
import { SceneExporter } from './sceneExporter';
|
|
9
9
|
import { SceneLoader } from './sceneLoader';
|
|
10
10
|
import { Viewport } from './controls';
|
|
11
|
+
import { createPointQuadGeometry } from './primitives/pointset';
|
|
12
|
+
import { createInstancedPointsMaterial } from './tls/pointsMaterial';
|
|
11
13
|
import {
|
|
12
14
|
createBufferGeometry,
|
|
13
15
|
createNewSpriteText,
|
|
@@ -1233,12 +1235,22 @@ const Scene = function (containerIn, rendererIn) {
|
|
|
1233
1235
|
* with clearTemporaryPrimitives method.
|
|
1234
1236
|
*/
|
|
1235
1237
|
this.addTemporaryPoints = (coords, colour) => {
|
|
1236
|
-
const geometry =
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
material.
|
|
1241
|
-
|
|
1238
|
+
const geometry = createPointQuadGeometry(coords.length);
|
|
1239
|
+
const material = createInstancedPointsMaterial(getCircularTexture());
|
|
1240
|
+
material.color.set(colour);
|
|
1241
|
+
material.size = 15;
|
|
1242
|
+
material.userData.uniforms.pointSize.value = 15;
|
|
1243
|
+
material.alphaTest = 0.5;
|
|
1244
|
+
const point = new InstancedPoints(geometry, material, coords.length);
|
|
1245
|
+
point.pointPositions = new Float32Array(coords.length * 3);
|
|
1246
|
+
const instancePosition = geometry.getAttribute('instancePosition');
|
|
1247
|
+
coords.forEach((coord, index) => {
|
|
1248
|
+
instancePosition.setXYZ(index, coord[0], coord[1], coord[2]);
|
|
1249
|
+
point.pointPositions[index * 3] = coord[0];
|
|
1250
|
+
point.pointPositions[index * 3 + 1] = coord[1];
|
|
1251
|
+
point.pointPositions[index * 3 + 2] = coord[2];
|
|
1252
|
+
});
|
|
1253
|
+
instancePosition.needsUpdate = true;
|
|
1242
1254
|
tempGroup.add(point);
|
|
1243
1255
|
return point;
|
|
1244
1256
|
}
|
package/src/sceneLoader.js
CHANGED
package/src/texture/texture.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as THREE from 'three';
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
2
|
import { Texture } from './texture';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -12,8 +12,15 @@ import { Texture } from './texture';
|
|
|
12
12
|
const TextureArray = function () {
|
|
13
13
|
Texture.call(this);
|
|
14
14
|
this.isTextureArray = true;
|
|
15
|
+
this.imageData = undefined;
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
this.setDataTexture = (dataTexture) => {
|
|
19
|
+
this.impl = dataTexture;
|
|
20
|
+
console.log("setDataTexture", dataTexture);
|
|
21
|
+
this.imageData = dataTexture.image.data;
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
/**
|
|
18
25
|
* Read images from an array containg src locations.
|
|
19
26
|
*
|
|
@@ -48,7 +55,7 @@ const TextureArray = function () {
|
|
|
48
55
|
length += data.length;
|
|
49
56
|
});
|
|
50
57
|
|
|
51
|
-
this.impl = new THREE.
|
|
58
|
+
this.impl = new THREE.Data3DTexture(fullArray, w, h, d);
|
|
52
59
|
this.size = {
|
|
53
60
|
width: w,
|
|
54
61
|
height: h,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BufferAttribute,
|
|
3
|
+
BufferGeometry,
|
|
3
4
|
ClampToEdgeWrapping,
|
|
4
5
|
DoubleSide,
|
|
5
6
|
InterpolateDiscrete,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
RepeatWrapping,
|
|
20
21
|
Scene,
|
|
21
22
|
Vector3
|
|
22
|
-
} from 'three';
|
|
23
|
+
} from 'three/webgpu';
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
class GLTFExporter {
|
|
@@ -1291,6 +1292,48 @@ class GLTFWriter {
|
|
|
1291
1292
|
|
|
1292
1293
|
}
|
|
1293
1294
|
|
|
1295
|
+
/**
|
|
1296
|
+
* A Pointset's {@link InstancedPoints} draws every point as an instance of a
|
|
1297
|
+
* small camera facing quad - its `geometry` only carries that quad, the
|
|
1298
|
+
* actual point positions/colours live in `pointPositions`/`instanceColor`.
|
|
1299
|
+
* Temporarily substitute a plain points geometry built from that data (and
|
|
1300
|
+
* flag the object as `isPoints`) so the regular POINTS export path below
|
|
1301
|
+
* produces a correct round trip, then return a function that restores the
|
|
1302
|
+
* object to its original state.
|
|
1303
|
+
*
|
|
1304
|
+
* @param {InstancedPoints} object Object to substitute the geometry of
|
|
1305
|
+
* @return {Function} Restores `object` to its pre-substitution state
|
|
1306
|
+
*/
|
|
1307
|
+
substituteInstancedPointsGeometry( object ) {
|
|
1308
|
+
|
|
1309
|
+
const count = object.count;
|
|
1310
|
+
const geometry = new BufferGeometry();
|
|
1311
|
+
geometry.setAttribute( 'position',
|
|
1312
|
+
new BufferAttribute( object.pointPositions.slice( 0, count * 3 ), 3 ) );
|
|
1313
|
+
|
|
1314
|
+
if ( object.instanceColor ) {
|
|
1315
|
+
|
|
1316
|
+
geometry.setAttribute( 'color',
|
|
1317
|
+
new BufferAttribute( object.instanceColor.array.slice( 0, count * 3 ), 3 ) );
|
|
1318
|
+
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
const originalGeometry = object.geometry;
|
|
1322
|
+
const originalIsPoints = object.isPoints;
|
|
1323
|
+
|
|
1324
|
+
object.geometry = geometry;
|
|
1325
|
+
object.isPoints = true;
|
|
1326
|
+
|
|
1327
|
+
return function () {
|
|
1328
|
+
|
|
1329
|
+
object.geometry = originalGeometry;
|
|
1330
|
+
object.isPoints = originalIsPoints;
|
|
1331
|
+
geometry.dispose();
|
|
1332
|
+
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1294
1337
|
/**
|
|
1295
1338
|
* Process mesh
|
|
1296
1339
|
* @param {THREE.Mesh} mesh Mesh to process
|
|
@@ -1887,10 +1930,20 @@ class GLTFWriter {
|
|
|
1887
1930
|
|
|
1888
1931
|
this.serializeUserData( object, nodeDef );
|
|
1889
1932
|
|
|
1890
|
-
if ( object.isMesh || object.isLine || object.isPoints ) {
|
|
1933
|
+
if ( object.isMesh || object.isLine || object.isPoints || object.isInstancedPoints ) {
|
|
1934
|
+
|
|
1935
|
+
let restoreInstancedPoints;
|
|
1936
|
+
|
|
1937
|
+
if ( object.isInstancedPoints ) {
|
|
1938
|
+
|
|
1939
|
+
restoreInstancedPoints = this.substituteInstancedPointsGeometry( object );
|
|
1940
|
+
|
|
1941
|
+
}
|
|
1891
1942
|
|
|
1892
1943
|
const meshIndex = this.processMesh( object );
|
|
1893
1944
|
|
|
1945
|
+
if ( restoreInstancedPoints ) restoreInstancedPoints();
|
|
1946
|
+
|
|
1894
1947
|
if ( meshIndex !== null ) nodeDef.mesh = meshIndex;
|
|
1895
1948
|
|
|
1896
1949
|
} else if ( object.isCamera ) {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InstancedMesh,
|
|
3
|
+
Matrix4,
|
|
4
|
+
Ray,
|
|
5
|
+
Vector3,
|
|
6
|
+
} from 'three/webgpu';
|
|
7
|
+
|
|
8
|
+
const _inverseMatrix = /*@__PURE__*/ new Matrix4();
|
|
9
|
+
const _ray = /*@__PURE__*/ new Ray();
|
|
10
|
+
const _position = /*@__PURE__*/ new Vector3();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* An {@link THREE.InstancedMesh} used to draw a {@link Pointset}. Every
|
|
14
|
+
* instance is a small quad billboarded towards the camera on the GPU (see
|
|
15
|
+
* {@link createInstancedPointsMaterial}), so the usual matrix/geometry based
|
|
16
|
+
* raycasting and bounding logic performed by `THREE.InstancedMesh` does not
|
|
17
|
+
* apply - the true, already time-blended location of every point is instead
|
|
18
|
+
* kept in `pointPositions` (local space) and used here directly, mirroring
|
|
19
|
+
* the distance-to-point approach the legacy `THREE.Points` override used.
|
|
20
|
+
*/
|
|
21
|
+
class InstancedPoints extends InstancedMesh {
|
|
22
|
+
|
|
23
|
+
constructor(geometry, material, count) {
|
|
24
|
+
super(geometry, material, count);
|
|
25
|
+
this.type = 'InstancedPoints';
|
|
26
|
+
this.isInstancedPoints = true;
|
|
27
|
+
this.frustumCulled = false;
|
|
28
|
+
this.pointSize = 10;
|
|
29
|
+
this.sizePerPixel = 1;
|
|
30
|
+
//Flat [x0, y0, z0, x1, y1, z1, ...] array of the current, already
|
|
31
|
+
//time-blended local positions of every active point.
|
|
32
|
+
this.pointPositions = new Float32Array(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
raycast(raycaster, intersects) {
|
|
36
|
+
const matrixWorld = this.matrixWorld;
|
|
37
|
+
const threshold = raycaster.params.Points ? raycaster.params.Points.threshold : 1;
|
|
38
|
+
const count = this.count;
|
|
39
|
+
const positions = this.pointPositions;
|
|
40
|
+
|
|
41
|
+
if (!count || !positions || positions.length < count * 3) return;
|
|
42
|
+
|
|
43
|
+
_inverseMatrix.copy(matrixWorld).invert();
|
|
44
|
+
_ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix);
|
|
45
|
+
|
|
46
|
+
const averageScale = (this.scale.x + this.scale.y + this.scale.z) / 3;
|
|
47
|
+
const localThreshold = threshold / averageScale * this.pointSize * this.sizePerPixel;
|
|
48
|
+
const localThresholdSq = localThreshold * localThreshold;
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < count; i++) {
|
|
51
|
+
_position.fromArray(positions, i * 3);
|
|
52
|
+
const rayPointDistanceSq = _ray.distanceSqToPoint(_position);
|
|
53
|
+
if (rayPointDistanceSq < localThresholdSq) {
|
|
54
|
+
const intersectPoint = new Vector3();
|
|
55
|
+
_ray.closestPointToPoint(_position, intersectPoint);
|
|
56
|
+
intersectPoint.applyMatrix4(matrixWorld);
|
|
57
|
+
const distance = raycaster.ray.origin.distanceTo(intersectPoint);
|
|
58
|
+
if (distance < raycaster.near || distance > raycaster.far) continue;
|
|
59
|
+
intersects.push({
|
|
60
|
+
distance: distance,
|
|
61
|
+
distanceToRay: Math.sqrt(rayPointDistanceSq),
|
|
62
|
+
point: intersectPoint,
|
|
63
|
+
index: i,
|
|
64
|
+
face: null,
|
|
65
|
+
object: this,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { InstancedPoints };
|
package/src/three/Loader.js
CHANGED
package/src/three/line/Line.js
CHANGED
|
@@ -8,12 +8,11 @@ import {
|
|
|
8
8
|
Mesh,
|
|
9
9
|
Sphere,
|
|
10
10
|
Vector3,
|
|
11
|
-
Vector4
|
|
12
|
-
|
|
11
|
+
Vector4,
|
|
12
|
+
Line2NodeMaterial,
|
|
13
|
+
Vector2
|
|
14
|
+
} from 'three/webgpu';
|
|
13
15
|
import { LineSegmentsGeometry } from './LineSegmentsGeometry.js';
|
|
14
|
-
import { LineMaterial } from './LineMaterial.js';
|
|
15
|
-
|
|
16
|
-
const _viewport = new Vector4();
|
|
17
16
|
|
|
18
17
|
const _start = new Vector3();
|
|
19
18
|
const _end = new Vector3();
|
|
@@ -30,6 +29,7 @@ const _closestPoint = new Vector3();
|
|
|
30
29
|
const _box = new Box3();
|
|
31
30
|
const _sphere = new Sphere();
|
|
32
31
|
const _clipToWorldVector = new Vector4();
|
|
32
|
+
const _viewport = new Vector4();
|
|
33
33
|
|
|
34
34
|
let _ray, _lineWidth;
|
|
35
35
|
|
|
@@ -94,10 +94,10 @@ function raycastWorldUnits( lineSegments, intersects ) {
|
|
|
94
94
|
function raycastScreenSpace( lineSegments, camera, intersects ) {
|
|
95
95
|
|
|
96
96
|
const projectionMatrix = camera.projectionMatrix;
|
|
97
|
-
const material = lineSegments.material;
|
|
98
|
-
const resolution = material.resolution;
|
|
99
97
|
const matrixWorld = lineSegments.matrixWorld;
|
|
100
98
|
|
|
99
|
+
const resolution = lineSegments._resolution;
|
|
100
|
+
|
|
101
101
|
const geometry = lineSegments.geometry;
|
|
102
102
|
const instanceStart = geometry.attributes.instanceStart;
|
|
103
103
|
const instanceEnd = geometry.attributes.instanceEnd;
|
|
@@ -231,22 +231,11 @@ function raycastScreenSpace( lineSegments, camera, intersects ) {
|
|
|
231
231
|
* to be in world units. {@link Line2} extends this object, forming a polyline instead of individual
|
|
232
232
|
* segments.
|
|
233
233
|
*
|
|
234
|
-
* This module can only be used with {@link
|
|
235
|
-
* import the class from `lines/
|
|
236
|
-
*
|
|
237
|
-
* ```js
|
|
238
|
-
* const geometry = new LineSegmentsGeometry();
|
|
239
|
-
* geometry.setPositions( positions );
|
|
240
|
-
* geometry.setColors( colors );
|
|
241
|
-
*
|
|
242
|
-
* const material = new LineMaterial( { linewidth: 5, vertexColors: true } };
|
|
243
|
-
*
|
|
244
|
-
* const lineSegments = new LineSegments2( geometry, material );
|
|
245
|
-
* scene.add( lineSegments );
|
|
246
|
-
* ```
|
|
234
|
+
* This module can only be used with {@link WebGPURenderer}. When using {@link WebGLRenderer},
|
|
235
|
+
* import the class from `lines/LineSegments2.js`.
|
|
247
236
|
*
|
|
248
237
|
* @augments Mesh
|
|
249
|
-
* @three_import import { LineSegments2 } from 'three/addons/lines/LineSegments2.js';
|
|
238
|
+
* @three_import import { LineSegments2 } from 'three/addons/lines/webgpu/LineSegments2.js';
|
|
250
239
|
*/
|
|
251
240
|
class LineSegments2 extends Mesh {
|
|
252
241
|
|
|
@@ -254,9 +243,9 @@ class LineSegments2 extends Mesh {
|
|
|
254
243
|
* Constructs a new wide line.
|
|
255
244
|
*
|
|
256
245
|
* @param {LineSegmentsGeometry} [geometry] - The line geometry.
|
|
257
|
-
* @param {
|
|
246
|
+
* @param {Line2NodeMaterial} [material] - The line material.
|
|
258
247
|
*/
|
|
259
|
-
constructor( geometry = new LineSegmentsGeometry(), material = new
|
|
248
|
+
constructor( geometry = new LineSegmentsGeometry(), material = new Line2NodeMaterial( { color: Math.random() * 0xffffff } ) ) {
|
|
260
249
|
|
|
261
250
|
super( geometry, material );
|
|
262
251
|
|
|
@@ -271,6 +260,8 @@ class LineSegments2 extends Mesh {
|
|
|
271
260
|
|
|
272
261
|
this.type = 'LineSegments2';
|
|
273
262
|
|
|
263
|
+
this._resolution = new Vector2();
|
|
264
|
+
|
|
274
265
|
}
|
|
275
266
|
|
|
276
267
|
/**
|
|
@@ -309,6 +300,13 @@ class LineSegments2 extends Mesh {
|
|
|
309
300
|
|
|
310
301
|
}
|
|
311
302
|
|
|
303
|
+
onBeforeRender( renderer ) {
|
|
304
|
+
|
|
305
|
+
renderer.getViewport( _viewport );
|
|
306
|
+
this._resolution.set( _viewport.z, _viewport.w );
|
|
307
|
+
|
|
308
|
+
}
|
|
309
|
+
|
|
312
310
|
/**
|
|
313
311
|
* Computes intersection points between a casted ray and this instance.
|
|
314
312
|
*
|
|
@@ -328,7 +326,7 @@ class LineSegments2 extends Mesh {
|
|
|
328
326
|
|
|
329
327
|
// early out if no resolution has been set (line was not rendered yet)
|
|
330
328
|
|
|
331
|
-
if ( worldUnits === false && ( this.
|
|
329
|
+
if ( worldUnits === false && ( this._resolution.x === 0 || this._resolution.y === 0 ) ) {
|
|
332
330
|
|
|
333
331
|
return;
|
|
334
332
|
|
|
@@ -362,7 +360,7 @@ class LineSegments2 extends Mesh {
|
|
|
362
360
|
} else {
|
|
363
361
|
|
|
364
362
|
const distanceToSphere = Math.max( camera.near, _sphere.distanceToPoint( _ray.origin ) );
|
|
365
|
-
sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere,
|
|
363
|
+
sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, this._resolution );
|
|
366
364
|
|
|
367
365
|
}
|
|
368
366
|
|
|
@@ -392,7 +390,7 @@ class LineSegments2 extends Mesh {
|
|
|
392
390
|
} else {
|
|
393
391
|
|
|
394
392
|
const distanceToBox = Math.max( camera.near, _box.distanceToPoint( _ray.origin ) );
|
|
395
|
-
boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox,
|
|
393
|
+
boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, this._resolution );
|
|
396
394
|
|
|
397
395
|
}
|
|
398
396
|
|
|
@@ -416,19 +414,6 @@ class LineSegments2 extends Mesh {
|
|
|
416
414
|
|
|
417
415
|
}
|
|
418
416
|
|
|
419
|
-
onBeforeRender( renderer ) {
|
|
420
|
-
|
|
421
|
-
const uniforms = this.material.uniforms;
|
|
422
|
-
|
|
423
|
-
if ( uniforms && uniforms.resolution ) {
|
|
424
|
-
|
|
425
|
-
renderer.getViewport( _viewport );
|
|
426
|
-
this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w );
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
|
|
432
417
|
}
|
|
433
418
|
|
|
434
419
|
export { LineSegments2 };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import { Fn, attribute, materialColor, materialOpacity, mix, uniform, vec4 } from 'three/tsl';
|
|
3
|
+
|
|
4
|
+
//Maps a classic material's constructor name to its NodeMaterial
|
|
5
|
+
//equivalent, since only NodeMaterial exposes colorNode.
|
|
6
|
+
const NODE_MATERIAL_CLASSES = {
|
|
7
|
+
MeshBasicMaterial: THREE.MeshBasicNodeMaterial,
|
|
8
|
+
MeshLambertMaterial: THREE.MeshLambertNodeMaterial,
|
|
9
|
+
MeshPhongMaterial: THREE.MeshPhongNodeMaterial,
|
|
10
|
+
MeshStandardMaterial: THREE.MeshStandardNodeMaterial,
|
|
11
|
+
LineBasicMaterial: THREE.LineBasicNodeMaterial,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Give `material` a colorNode that blends between the two morph colour
|
|
16
|
+
* targets {@link updateMorphColorAttribute} (in utilities.js) keeps
|
|
17
|
+
* published as the 'morphColor0'/'morphColor1' geometry attributes -
|
|
18
|
+
* whichever two morph targets currently have non-zero influence.
|
|
19
|
+
*
|
|
20
|
+
* This replaces the legacy `material.onBeforeCompile = augmentMorphColor`
|
|
21
|
+
* approach, which patched raw GLSL into the classic WebGL shader and has no
|
|
22
|
+
* effect once a material is compiled through the WebGPU/TSL pipeline.
|
|
23
|
+
* three.js's own built-in WebGPU morph target system packs morph colour
|
|
24
|
+
* data into its morph texture (see three's Morph.js) but its blend loop
|
|
25
|
+
* only ever applies the result to position/normal, never colour, so this
|
|
26
|
+
* has to be done by hand.
|
|
27
|
+
*
|
|
28
|
+
* Converts `material` to its NodeMaterial equivalent first if it isn't one
|
|
29
|
+
* already, since only NodeMaterial exposes `colorNode`.
|
|
30
|
+
*
|
|
31
|
+
* @param {THREE.Material} material - Material to give the morph colour
|
|
32
|
+
* blend to; only used for its constructor type if not already a
|
|
33
|
+
* NodeMaterial - all of its usual properties (color, opacity, map, side,
|
|
34
|
+
* etc.) are preserved.
|
|
35
|
+
* @return {THREE.NodeMaterial} The (possibly newly converted) material.
|
|
36
|
+
* Its `userData.uniforms.morphColorMix` uniform drives the blend (0 = fully
|
|
37
|
+
* morphColor0, 1 = fully morphColor1) - kept in sync automatically by
|
|
38
|
+
* updateMorphColorAttribute.
|
|
39
|
+
*/
|
|
40
|
+
const applyMorphColorNode = (material) => {
|
|
41
|
+
let target = material;
|
|
42
|
+
if (!target.isNodeMaterial) {
|
|
43
|
+
const NodeMaterialClass = NODE_MATERIAL_CLASSES[material.type] || THREE.MeshBasicNodeMaterial;
|
|
44
|
+
target = new NodeMaterialClass();
|
|
45
|
+
target.copy(material);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const morphColorMix = uniform(0);
|
|
49
|
+
|
|
50
|
+
//materialColor already folds in material.color and, if present, .map -
|
|
51
|
+
//multiplying it by the blended per vertex morph colour keeps that
|
|
52
|
+
//compositing instead of replacing it outright.
|
|
53
|
+
target.colorNode = Fn(() => {
|
|
54
|
+
const colorA = attribute('morphColor0', 'vec3');
|
|
55
|
+
const colorB = attribute('morphColor1', 'vec3');
|
|
56
|
+
const blended = mix(colorA, colorB, morphColorMix);
|
|
57
|
+
return vec4(blended.mul(materialColor), materialOpacity);
|
|
58
|
+
})();
|
|
59
|
+
|
|
60
|
+
target.userData.uniforms = { ...target.userData.uniforms, morphColorMix };
|
|
61
|
+
|
|
62
|
+
return target;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export { applyMorphColorNode };
|