@lijuhong1981/three.instancedsprite 1.0.0 → 1.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/API.md CHANGED
@@ -22,6 +22,12 @@
22
22
  <dt><a href="#InstancedSpriteMesh">InstancedSpriteMesh</a> ⇐ <code>Mesh</code></dt>
23
23
  <dd><p>InstancedSpriteMesh类,基于InstancedBufferGeometry实现的高性能InstancedSprite渲染组件</p>
24
24
  </dd>
25
+ <dt><a href="#InstancedSpriteNodeMaterial">InstancedSpriteNodeMaterial</a> ⇐ <code>NodeMaterial</code></dt>
26
+ <dd><p>InstancedSpriteNodeMaterial 材质类,基于 Three.js TSL (Three Shading Language) 语法实现</p>
27
+ <p>功能与 InstancedSpriteMaterial (ShaderMaterial) 完全相同,但使用 TSL 节点系统构建,
28
+ 可更好地与 Three.js 的 NodeMaterial 管线集成(自动处理色调映射、色彩空间转换等)。</p>
29
+ <p><strong>注意</strong>:使用此类需要 Three.js 的 WebGPU/TSL 构建(<code>three/webgpu</code>),非标准 <code>three</code> 构建。</p>
30
+ </dd>
25
31
  </dl>
26
32
 
27
33
  ## Constants
@@ -62,6 +68,7 @@ InstancedSprite 数据模型类,用于存储单个 InstancedSprite 的所有
62
68
  * [.color](#InstancedSprite+color) : <code>Color</code>
63
69
  * [.opacity](#InstancedSprite+opacity) : <code>number</code>
64
70
  * [.imageSize](#InstancedSprite+imageSize) : <code>Vector2</code>
71
+ * [.userData](#InstancedSprite+userData) : <code>object</code>
65
72
  * [.isInstancedSprite](#InstancedSprite+isInstancedSprite) : <code>boolean</code>
66
73
  * [.visible](#InstancedSprite+visible) : <code>boolean</code>
67
74
  * [.rotationDegrees](#InstancedSprite+rotationDegrees) : <code>number</code>
@@ -70,7 +77,7 @@ InstancedSprite 数据模型类,用于存储单个 InstancedSprite 的所有
70
77
  * [.imageWidth](#InstancedSprite+imageWidth) : <code>number</code>
71
78
  * [.imageHeight](#InstancedSprite+imageHeight) : <code>number</code>
72
79
  * [.geometry](#InstancedSprite+geometry) : <code>InstancedBufferGeometry</code>
73
- * [.material](#InstancedSprite+material) : [<code>InstancedSpriteMaterial</code>](#InstancedSpriteMaterial)
80
+ * [.material](#InstancedSprite+material) : [<code>InstancedSpriteMaterial</code>](#InstancedSpriteMaterial) \| [<code>InstancedSpriteNodeMaterial</code>](#InstancedSpriteNodeMaterial)
74
81
  * [.setValues(options)](#InstancedSprite+setValues) ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
75
82
  * [.remove()](#InstancedSprite+remove) ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
76
83
  * [.raycast(raycaster, intersects, modelViewMatrix)](#InstancedSprite+raycast)
@@ -151,6 +158,13 @@ InstancedSprite 数据模型类,用于存储单个 InstancedSprite 的所有
151
158
  ### instancedSprite.imageSize : <code>Vector2</code>
152
159
  图片尺寸(像素),图片加载完成后可用
153
160
 
161
+ **Kind**: instance property of [<code>InstancedSprite</code>](#InstancedSprite)
162
+ **Read only**: true
163
+ <a name="InstancedSprite+userData"></a>
164
+
165
+ ### instancedSprite.userData : <code>object</code>
166
+ 用户自定义数据存储对象,InstancedSprite本身不使用该属性,用户可以自由使用它来存储任意数据
167
+
154
168
  **Kind**: instance property of [<code>InstancedSprite</code>](#InstancedSprite)
155
169
  **Read only**: true
156
170
  <a name="InstancedSprite+isInstancedSprite"></a>
@@ -208,8 +222,8 @@ InstancedSprite对象的几何体属性
208
222
  **Read only**: true
209
223
  <a name="InstancedSprite+material"></a>
210
224
 
211
- ### instancedSprite.material : [<code>InstancedSpriteMaterial</code>](#InstancedSpriteMaterial)
212
- InstancedSprite对象的材质属性
225
+ ### instancedSprite.material : [<code>InstancedSpriteMaterial</code>](#InstancedSpriteMaterial) \| [<code>InstancedSpriteNodeMaterial</code>](#InstancedSpriteNodeMaterial)
226
+ InstancedSprite对象的材质属性,可能是InstancedSpriteMaterial或InstancedSpriteNodeMaterial
213
227
 
214
228
  **Kind**: instance property of [<code>InstancedSprite</code>](#InstancedSprite)
215
229
  **Read only**: true
@@ -256,6 +270,8 @@ InstancedSpriteCollection类,批量管理InstancedSprite实例
256
270
  **Extends**: <code>Object3D</code>
257
271
 
258
272
  * [InstancedSpriteCollection](#InstancedSpriteCollection) ⇐ <code>Object3D</code>
273
+ * [new InstancedSpriteCollection([useNodeMaterial])](#new_InstancedSpriteCollection_new)
274
+ * [.useNodeMaterial](#InstancedSpriteCollection+useNodeMaterial) : <code>boolean</code>
259
275
  * [.type](#InstancedSpriteCollection+type) : <code>string</code>
260
276
  * [.isInstancedSpriteCollection](#InstancedSpriteCollection+isInstancedSpriteCollection) : <code>boolean</code>
261
277
  * [.depthTest](#InstancedSpriteCollection+depthTest) : <code>boolean</code>
@@ -269,6 +285,22 @@ InstancedSpriteCollection类,批量管理InstancedSprite实例
269
285
  * [.forEach(callback)](#InstancedSpriteCollection+forEach) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
270
286
  * [.raycast(raycaster, intersects)](#InstancedSpriteCollection+raycast)
271
287
 
288
+ <a name="new_InstancedSpriteCollection_new"></a>
289
+
290
+ ### new InstancedSpriteCollection([useNodeMaterial])
291
+
292
+ | Param | Type | Default | Description |
293
+ | --- | --- | --- | --- |
294
+ | [useNodeMaterial] | <code>boolean</code> | <code>false</code> | 是否使用TSL的NodeMaterial,默认false |
295
+
296
+ <a name="InstancedSpriteCollection+useNodeMaterial"></a>
297
+
298
+ ### instancedSpriteCollection.useNodeMaterial : <code>boolean</code>
299
+ 是否使用TSL的NodeMaterial,默认false
300
+
301
+ **Kind**: instance property of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
302
+ **Default**: <code>false</code>
303
+ **Read only**: true
272
304
  <a name="InstancedSpriteCollection+type"></a>
273
305
 
274
306
  ### instancedSpriteCollection.type : <code>string</code>
@@ -485,6 +517,24 @@ Computes intersection points between a casted ray and this sprite.
485
517
  | raycaster | <code>Raycaster</code> | The raycaster. |
486
518
  | intersects | <code>Array.&lt;Object&gt;</code> | The target array that holds the intersection points. |
487
519
 
520
+ <a name="InstancedSpriteNodeMaterial"></a>
521
+
522
+ ## InstancedSpriteNodeMaterial ⇐ <code>NodeMaterial</code>
523
+ InstancedSpriteNodeMaterial 材质类,基于 Three.js TSL (Three Shading Language) 语法实现
524
+
525
+ 功能与 InstancedSpriteMaterial (ShaderMaterial) 完全相同,但使用 TSL 节点系统构建,
526
+ 可更好地与 Three.js 的 NodeMaterial 管线集成(自动处理色调映射、色彩空间转换等)。
527
+
528
+ **注意**:使用此类需要 Three.js 的 WebGPU/TSL 构建(`three/webgpu`),非标准 `three` 构建。
529
+
530
+ **Kind**: global class
531
+ **Extends**: <code>NodeMaterial</code>
532
+ <a name="InstancedSpriteNodeMaterial+texture"></a>
533
+
534
+ ### instancedSpriteNodeMaterial.texture : <code>Texture</code> \| <code>null</code>
535
+ 图片纹理
536
+
537
+ **Kind**: instance property of [<code>InstancedSpriteNodeMaterial</code>](#InstancedSpriteNodeMaterial)
488
538
  <a name="imageLoader"></a>
489
539
 
490
540
  ## imageLoader
@@ -492,6 +542,7 @@ Computes intersection points between a casted ray and this sprite.
492
542
  **Import**: InstancedSpriteCollection from "./InstancedSpriteCollection.js";
493
543
  **Import**: InstancedSpriteMesh from "./InstancedSpriteMesh.js";
494
544
  **Import**: InstancedSpriteMaterial from "./InstancedSpriteMaterial.js";
545
+ **Import**: InstancedSpriteNodeMaterial from "./InstancedSpriteNodeMaterial.js";
495
546
  <a name="InstancedSpriteOptions"></a>
496
547
 
497
548
  ## InstancedSpriteOptions : <code>object</code>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lijuhong1981/three.instancedsprite",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "module": "index.js",
@@ -8,6 +8,7 @@ import { Color, InstancedBufferGeometry, MathUtils, Matrix4, Triangle, Vector2,
8
8
  * @import InstancedSpriteCollection from "./InstancedSpriteCollection.js";
9
9
  * @import InstancedSpriteMesh from "./InstancedSpriteMesh.js";
10
10
  * @import InstancedSpriteMaterial from "./InstancedSpriteMaterial.js";
11
+ * @import InstancedSpriteNodeMaterial from "./InstancedSpriteNodeMaterial.js";
11
12
  */
12
13
 
13
14
  const imageLoader = new ImageLoader({ cacheType: Loader.CacheType.ALONE, });
@@ -169,6 +170,28 @@ class InstancedSprite {
169
170
  this.imageSize = new Vector2(0, 0);
170
171
  this._imageSize = new Vector2(0, 0);
171
172
  this._image = null;
173
+ /**
174
+ * 拾取颜色,用于GPU拾取,由Picking管理器设置和使用,用户无需关心
175
+ * @type {Color}
176
+ * @readonly
177
+ * @private
178
+ */
179
+ this.pickColor = new Color();
180
+ this._pickColor = new Color();
181
+ /**
182
+ * 是否启用拾取颜色,用于GPU拾取,由Picking管理器设置和使用,用户无需关心
183
+ * @type {boolean}
184
+ * @readonly
185
+ * @private
186
+ */
187
+ this.enablePickColor = false;
188
+ this._enablePickColor = false;
189
+ /**
190
+ * 用户自定义数据存储对象,InstancedSprite本身不使用该属性,用户可以自由使用它来存储任意数据
191
+ * @type {object}
192
+ * @readonly
193
+ */
194
+ this.userData = {};
172
195
 
173
196
  this.setValues(options);
174
197
  }
@@ -249,8 +272,8 @@ class InstancedSprite {
249
272
  return this._mesh ? this._mesh.geometry : undefined;
250
273
  }
251
274
  /**
252
- * InstancedSprite对象的材质属性
253
- * @type {InstancedSpriteMaterial}
275
+ * InstancedSprite对象的材质属性,可能是InstancedSpriteMaterial或InstancedSpriteNodeMaterial
276
+ * @type {InstancedSpriteMaterial|InstancedSpriteNodeMaterial}
254
277
  * @readonly
255
278
  */
256
279
  get material() {
@@ -13,10 +13,12 @@ attribute vec4 aPositionAndShow; // xyz: InstancedSprite位置(世界空间)
13
13
  attribute vec4 aCenterAndSize; // xy: 锚点中心(0-1), zw: 图片宽高(像素/米)
14
14
  attribute vec3 aScaleAndRotationAndSizeAttenuation; // x: 缩放, y: 旋转(弧度), z: 大小跟随相机深度(0/1)
15
15
  attribute vec4 aColorAndOpacity; // RGBA颜色
16
+ attribute vec4 aPickColorAndEnabled; // xyz:拾取颜色,w:是否启用拾取颜色(0/1)
16
17
 
17
18
  varying float vShow;
18
19
  varying vec2 vUv;
19
20
  varying vec4 vColorAndOpacity;
21
+ varying vec4 vPickColorAndEnabled;
20
22
 
21
23
  void main() {
22
24
  // --- 1. 提前解包属性(GPU会自动优化,无性能损失)---
@@ -31,6 +33,7 @@ void main() {
31
33
  vShow = show;
32
34
  vUv = uv;
33
35
  vColorAndOpacity = aColorAndOpacity;
36
+ vPickColorAndEnabled = aPickColorAndEnabled;
34
37
 
35
38
  // --- 3. 提前隐藏不可见物体(顶点级丢弃,性能最优)---
36
39
  if (show < 0.5 || imageSize.x <= 0.0 || imageSize.y <= 0.0) {
@@ -82,21 +85,31 @@ uniform sampler2D uTexture;
82
85
  varying float vShow;
83
86
  varying vec2 vUv;
84
87
  varying vec4 vColorAndOpacity;
88
+ varying vec4 vPickColorAndEnabled;
85
89
 
86
90
  void main() {
87
- vec4 texColor = texture2D(uTexture, vUv);
88
- vec4 diffuseColor = texColor * vColorAndOpacity;
89
-
90
- // 丢弃完全透明的像素
91
- if (diffuseColor.a < 0.005 || vShow < 0.5) {
91
+ if (vShow < 0.5) {
92
92
  discard;
93
93
  }
94
94
 
95
- gl_FragColor = diffuseColor;
95
+ float enablePickColor = vPickColorAndEnabled.w;
96
+
97
+ if (enablePickColor > 0.5){
98
+ gl_FragColor = vec4(vPickColorAndEnabled.xyz, 1.0);
99
+ } else {
100
+ vec4 texColor = texture2D(uTexture, vUv);
101
+ vec4 diffuseColor = texColor * vColorAndOpacity;
96
102
 
97
- #include <logdepthbuf_fragment>
98
- #include <tonemapping_fragment>
99
- #include <colorspace_fragment>
103
+ // 丢弃完全透明的像素
104
+ if (diffuseColor.a < 0.005) {
105
+ discard;
106
+ }
107
+
108
+ gl_FragColor = diffuseColor;
109
+ #include <logdepthbuf_fragment>
110
+ #include <tonemapping_fragment>
111
+ #include <colorspace_fragment>
112
+ }
100
113
  }
101
114
  `;
102
115
 
@@ -36,6 +36,7 @@ const aPositionAndShow = 'aPositionAndShow';
36
36
  const aCenterAndSize = 'aCenterAndSize';
37
37
  const aScaleAndRotationAndSizeAttenuation = 'aScaleAndRotationAndSizeAttenuation';
38
38
  const aColorAndOpacity = 'aColorAndOpacity';
39
+ const aPickColorAndEnabled = 'aPickColorAndEnabled';
39
40
  /**
40
41
  * InstancedSpriteMaterial使用的attribute名称常量与itemSize大小,InstancedSpriteMesh会根据名称和itemSize创建InstancedBufferAttribute
41
42
  * @type {Object<string, number>}
@@ -47,6 +48,7 @@ const AttributesItemSize = Object.freeze({
47
48
  aCenterAndSize: 4,
48
49
  aScaleAndRotationAndSizeAttenuation: 3,
49
50
  aColorAndOpacity: 4,
51
+ aPickColorAndEnabled: 4,
50
52
  });
51
53
  /**
52
54
  * 检查并更新一个InstancedSprite实例的数据到对应的InstancedBufferAttribute位置
@@ -67,6 +69,8 @@ function checkAndUpdateInstancedSprite(mesh, sprite) {
67
69
  const sizeAttenuationChanged = (sprite._sizeAttenuation !== sprite.sizeAttenuation);
68
70
  const colorChanged = (sprite._color.equals(sprite.color) === false);
69
71
  const opacityChanged = (sprite._opacity !== sprite.opacity);
72
+ const pickColorChanged = (sprite._pickColor.equals(sprite.pickColor) === false);
73
+ const enablePickColorChanged = (sprite._enablePickColor !== sprite.enablePickColor);
70
74
 
71
75
  let idx = 0;
72
76
 
@@ -131,6 +135,21 @@ function checkAndUpdateInstancedSprite(mesh, sprite) {
131
135
  }
132
136
  mesh.geometry.attributes.aColorAndOpacity.needsUpdate = true;
133
137
  }
138
+
139
+ if (pickColorChanged || enablePickColorChanged) {
140
+ idx = index * AttributesItemSize.aPickColorAndEnabled;
141
+ if (pickColorChanged) {
142
+ sprite._pickColor.copy(sprite.pickColor);
143
+ attributesData.aPickColorAndEnabled[idx] = sprite._pickColor.r;
144
+ attributesData.aPickColorAndEnabled[idx + 1] = sprite._pickColor.g;
145
+ attributesData.aPickColorAndEnabled[idx + 2] = sprite._pickColor.b;
146
+ }
147
+ if (enablePickColorChanged) {
148
+ sprite._enablePickColor = sprite.enablePickColor;
149
+ attributesData.aPickColorAndEnabled[idx + 3] = sprite._enablePickColor ? 1 : 0;
150
+ }
151
+ mesh.geometry.attributes.aPickColorAndEnabled.needsUpdate = true;
152
+ }
134
153
  };
135
154
  /**
136
155
  * 添加一个InstancedSprite实例的数据到InstancedBufferAttribute中对应的位置
@@ -42,6 +42,7 @@ class InstancedSpriteNodeMaterial extends NodeMaterial {
42
42
  const aCenterAndSize = attribute('aCenterAndSize', 'vec4');
43
43
  const aScaleAndRotationAndSizeAttenuation = attribute('aScaleAndRotationAndSizeAttenuation', 'vec3');
44
44
  const aColorAndOpacity = attribute('aColorAndOpacity', 'vec4');
45
+ const aPickColorAndEnabled = attribute('aPickColorAndEnabled', 'vec4');
45
46
 
46
47
  // ============================================================
47
48
  // Varying 变量 — 从顶点着色器传递到片元着色器
@@ -49,6 +50,7 @@ class InstancedSpriteNodeMaterial extends NodeMaterial {
49
50
  const vShow = varying(float(1));
50
51
  const vColorAndOpacity = varying(vec4(1));
51
52
  const vUv = varying(vec2(1));
53
+ const vPickColorAndEnabled = varying(vec4(1));
52
54
 
53
55
  // ============================================================
54
56
  // 顶点着色器 (vertexNode)
@@ -66,6 +68,7 @@ class InstancedSpriteNodeMaterial extends NodeMaterial {
66
68
  vShow.assign(show);
67
69
  vColorAndOpacity.assign(aColorAndOpacity);
68
70
  vUv.assign(uv());
71
+ vPickColorAndEnabled.assign(aPickColorAndEnabled);
69
72
 
70
73
  // --- 3. 计算模型视图位置 ---
71
74
  const mvPosition = modelViewMatrix.mul(vec4(aPositionAndShow.xyz, 1));
@@ -122,12 +125,24 @@ class InstancedSpriteNodeMaterial extends NodeMaterial {
122
125
  // 片元着色器 (fragmentNode)
123
126
  // ============================================================
124
127
  this.fragmentNode = Fn(() => {
125
- // 采样纹理
126
- const texColor = texture(this._textureNode, vUv);
127
- const diffuseColor = texColor.mul(vColorAndOpacity);
128
+ Discard(vShow.lessThan(0.5));
128
129
 
129
- // 丢弃完全透明或隐藏的像素
130
- Discard(diffuseColor.a.lessThan(0.005).or(vShow.lessThan(0.5)));
130
+ const enablePickColor = vPickColorAndEnabled.w.greaterThan(0.5);
131
+ const diffuseColor = vec4(0, 0, 0, 1).toVar('diffuseColor');
132
+
133
+ If(enablePickColor, () => {
134
+ // 拾取模式:直接输出拾取颜色,不受纹理/透明度影响
135
+ diffuseColor.assign(vec4(vPickColorAndEnabled.xyz, 1));
136
+ }).Else(() => {
137
+ // 采样纹理
138
+ const texColor = texture(this._textureNode, vUv);
139
+ const color = texColor.mul(vColorAndOpacity);
140
+
141
+ // 丢弃完全透明的像素
142
+ Discard(color.a.lessThan(0.005));
143
+
144
+ diffuseColor.assign(color);
145
+ });
131
146
 
132
147
  return diffuseColor;
133
148
  }).once();
@@ -142,7 +157,7 @@ class InstancedSpriteNodeMaterial extends NodeMaterial {
142
157
  set texture(value) {
143
158
  this._textureNode.value = value;
144
159
  }
145
- }
160
+ };
146
161
 
147
162
  export default InstancedSpriteNodeMaterial;
148
163
  export { InstancedSpriteNodeMaterial };