@lijuhong1981/three.instancedsprite 1.0.1 → 2.0.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/API.md +213 -10
- package/README.md +146 -55
- package/index.js +6 -5
- package/package.json +11 -4
- package/src/InstancedSprite.js +14 -1
- package/src/InstancedSpriteCollection.js +205 -57
- package/src/InstancedSpriteMaterial.js +154 -147
- package/src/InstancedSpriteMesh.js +510 -425
- package/src/InstancedSpriteNodeMaterial.js +12 -5
- package/src/TextureAtlas.js +125 -0
- package/.claude/settings.local.json +0 -7
package/API.md
CHANGED
|
@@ -8,26 +8,40 @@
|
|
|
8
8
|
<li>但它可以作为属性Module使用,修改InstancedSprite的属性会自动更新至GPU中</li>
|
|
9
9
|
</ul>
|
|
10
10
|
</dd>
|
|
11
|
+
<dt><a href="#Billboard">Billboard</a></dt>
|
|
12
|
+
<dd></dd>
|
|
11
13
|
<dt><a href="#InstancedSpriteCollection">InstancedSpriteCollection</a> ⇐ <code>Object3D</code></dt>
|
|
12
14
|
<dd><p>InstancedSpriteCollection类,批量管理InstancedSprite实例</p>
|
|
13
15
|
<ul>
|
|
14
16
|
<li>继承自Object3D</li>
|
|
15
|
-
<li
|
|
16
|
-
<li
|
|
17
|
+
<li>使用纹理图集将不同图片打包,一张图集对应一个 InstancedSpriteMesh(一次 draw call)</li>
|
|
18
|
+
<li>图集扩容到上限后会新建图集与 Mesh</li>
|
|
17
19
|
</ul>
|
|
18
20
|
</dd>
|
|
21
|
+
<dt><a href="#BillboardCollection">BillboardCollection</a></dt>
|
|
22
|
+
<dd></dd>
|
|
19
23
|
<dt><a href="#InstancedSpriteMaterial">InstancedSpriteMaterial</a> ⇐ <code>ShaderMaterial</code></dt>
|
|
20
24
|
<dd><p>InstancedSprite 材质类,以attribute形式传入InstancedSprite对象实例属性</p>
|
|
21
25
|
</dd>
|
|
26
|
+
<dt><a href="#BillboardMaterial">BillboardMaterial</a></dt>
|
|
27
|
+
<dd></dd>
|
|
22
28
|
<dt><a href="#InstancedSpriteMesh">InstancedSpriteMesh</a> ⇐ <code>Mesh</code></dt>
|
|
23
29
|
<dd><p>InstancedSpriteMesh类,基于InstancedBufferGeometry实现的高性能InstancedSprite渲染组件</p>
|
|
30
|
+
<p>一张图集纹理对应一个 InstancedSpriteMesh,所有使用该图集的 Sprite 由其统一绘制</p>
|
|
24
31
|
</dd>
|
|
32
|
+
<dt><a href="#BillboardMesh">BillboardMesh</a></dt>
|
|
33
|
+
<dd></dd>
|
|
25
34
|
<dt><a href="#InstancedSpriteNodeMaterial">InstancedSpriteNodeMaterial</a> ⇐ <code>NodeMaterial</code></dt>
|
|
26
35
|
<dd><p>InstancedSpriteNodeMaterial 材质类,基于 Three.js TSL (Three Shading Language) 语法实现</p>
|
|
27
36
|
<p>功能与 InstancedSpriteMaterial (ShaderMaterial) 完全相同,但使用 TSL 节点系统构建,
|
|
28
37
|
可更好地与 Three.js 的 NodeMaterial 管线集成(自动处理色调映射、色彩空间转换等)。</p>
|
|
29
38
|
<p><strong>注意</strong>:使用此类需要 Three.js 的 WebGPU/TSL 构建(<code>three/webgpu</code>),非标准 <code>three</code> 构建。</p>
|
|
30
39
|
</dd>
|
|
40
|
+
<dt><a href="#BillboardNodeMaterial">BillboardNodeMaterial</a></dt>
|
|
41
|
+
<dd></dd>
|
|
42
|
+
<dt><a href="#TextureAtlas">TextureAtlas</a></dt>
|
|
43
|
+
<dd><p>纹理图集,将多张图片按行(shelf)打包进一张 Canvas 纹理,用于合并 draw call</p>
|
|
44
|
+
</dd>
|
|
31
45
|
</dl>
|
|
32
46
|
|
|
33
47
|
## Constants
|
|
@@ -257,41 +271,58 @@ Computes intersection points between a casted ray and this sprite.
|
|
|
257
271
|
| intersects | <code>Array.<Object></code> | The target array that holds the intersection points. |
|
|
258
272
|
| modelViewMatrix | <code>Matrix4</code> | |
|
|
259
273
|
|
|
274
|
+
<a name="Billboard"></a>
|
|
275
|
+
|
|
276
|
+
## Billboard
|
|
277
|
+
**Kind**: global class
|
|
278
|
+
<a name="new_Billboard_new"></a>
|
|
279
|
+
|
|
280
|
+
### new Billboard()
|
|
281
|
+
InstancedSprite 的别名(广告牌语义)。
|
|
282
|
+
|
|
260
283
|
<a name="InstancedSpriteCollection"></a>
|
|
261
284
|
|
|
262
285
|
## InstancedSpriteCollection ⇐ <code>Object3D</code>
|
|
263
286
|
InstancedSpriteCollection类,批量管理InstancedSprite实例
|
|
264
287
|
|
|
265
288
|
* 继承自Object3D
|
|
266
|
-
*
|
|
267
|
-
*
|
|
289
|
+
* 使用纹理图集将不同图片打包,一张图集对应一个 InstancedSpriteMesh(一次 draw call)
|
|
290
|
+
* 图集扩容到上限后会新建图集与 Mesh
|
|
268
291
|
|
|
269
292
|
**Kind**: global class
|
|
270
293
|
**Extends**: <code>Object3D</code>
|
|
271
294
|
|
|
272
295
|
* [InstancedSpriteCollection](#InstancedSpriteCollection) ⇐ <code>Object3D</code>
|
|
273
|
-
* [new InstancedSpriteCollection([
|
|
296
|
+
* [new InstancedSpriteCollection([options])](#new_InstancedSpriteCollection_new)
|
|
274
297
|
* [.useNodeMaterial](#InstancedSpriteCollection+useNodeMaterial) : <code>boolean</code>
|
|
275
298
|
* [.type](#InstancedSpriteCollection+type) : <code>string</code>
|
|
276
299
|
* [.isInstancedSpriteCollection](#InstancedSpriteCollection+isInstancedSpriteCollection) : <code>boolean</code>
|
|
277
300
|
* [.depthTest](#InstancedSpriteCollection+depthTest) : <code>boolean</code>
|
|
301
|
+
* [.depthWrite](#InstancedSpriteCollection+depthWrite) : <code>boolean</code>
|
|
278
302
|
* [.instancedSprites](#InstancedSpriteCollection+instancedSprites) : [<code>Array.<InstancedSprite></code>](#InstancedSprite)
|
|
279
303
|
* [.size](#InstancedSpriteCollection+size) : <code>number</code>
|
|
280
304
|
* [._setImage(source, sprite)](#InstancedSpriteCollection+_setImage)
|
|
281
305
|
* [.get(index)](#InstancedSpriteCollection+get) ⇒ [<code>InstancedSprite</code>](#InstancedSprite) \| <code>undefined</code>
|
|
282
306
|
* [.getByUuid(uuid)](#InstancedSpriteCollection+getByUuid) ⇒ [<code>InstancedSprite</code>](#InstancedSprite) \| <code>undefined</code>
|
|
283
|
-
* [.add()](#InstancedSpriteCollection+add) ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
|
|
307
|
+
* [.add(options)](#InstancedSpriteCollection+add) ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
|
|
284
308
|
* [.remove(sprite)](#InstancedSpriteCollection+remove) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
309
|
+
* [.clear()](#InstancedSpriteCollection+clear) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
310
|
+
* [.reserve(capacity)](#InstancedSpriteCollection+reserve) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
285
311
|
* [.forEach(callback)](#InstancedSpriteCollection+forEach) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
286
312
|
* [.raycast(raycaster, intersects)](#InstancedSpriteCollection+raycast)
|
|
313
|
+
* [.dispose()](#InstancedSpriteCollection+dispose) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
287
314
|
|
|
288
315
|
<a name="new_InstancedSpriteCollection_new"></a>
|
|
289
316
|
|
|
290
|
-
### new InstancedSpriteCollection([
|
|
317
|
+
### new InstancedSpriteCollection([options])
|
|
291
318
|
|
|
292
319
|
| Param | Type | Default | Description |
|
|
293
320
|
| --- | --- | --- | --- |
|
|
294
|
-
| [
|
|
321
|
+
| [options] | <code>object</code> | | 配置项 |
|
|
322
|
+
| [options.useNodeMaterial] | <code>boolean</code> | <code>false</code> | 是否使用TSL的NodeMaterial(WebGPU),默认false |
|
|
323
|
+
| [options.initialSize] | <code>number</code> | <code>1024</code> | 图集初始边长 |
|
|
324
|
+
| [options.maxSize] | <code>number</code> | <code>8192</code> | 图集最大边长 |
|
|
325
|
+
| [options.padding] | <code>number</code> | <code>2</code> | 子图间距 |
|
|
295
326
|
|
|
296
327
|
<a name="InstancedSpriteCollection+useNodeMaterial"></a>
|
|
297
328
|
|
|
@@ -320,6 +351,13 @@ InstancedSpriteCollection对象标识
|
|
|
320
351
|
### instancedSpriteCollection.depthTest : <code>boolean</code>
|
|
321
352
|
深度测试开关,默认为true,开启后会进行深度测试以正确处理遮挡关系,但可能会有性能影响;如果关闭则所有InstancedSprite都会被渲染在最前面,适合需要始终显示的UI元素等场景
|
|
322
353
|
|
|
354
|
+
**Kind**: instance property of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
355
|
+
**Default**: <code>true</code>
|
|
356
|
+
<a name="InstancedSpriteCollection+depthWrite"></a>
|
|
357
|
+
|
|
358
|
+
### instancedSpriteCollection.depthWrite : <code>boolean</code>
|
|
359
|
+
深度写入开关,默认为true;多个半透明 Sprite 重叠时,开启深度写入可能导致排序瑕疵(后方 Sprite 被错误遮挡),关闭可缓解,适合半透明标签/粒子等场景
|
|
360
|
+
|
|
323
361
|
**Kind**: instance property of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
324
362
|
**Default**: <code>true</code>
|
|
325
363
|
<a name="InstancedSpriteCollection+instancedSprites"></a>
|
|
@@ -370,10 +408,15 @@ InstancedSprite实例数量
|
|
|
370
408
|
|
|
371
409
|
<a name="InstancedSpriteCollection+add"></a>
|
|
372
410
|
|
|
373
|
-
### instancedSpriteCollection.add() ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
|
|
411
|
+
### instancedSpriteCollection.add(options) ⇒ [<code>InstancedSprite</code>](#InstancedSprite)
|
|
374
412
|
添加InstancedSprite
|
|
375
413
|
|
|
376
414
|
**Kind**: instance method of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
415
|
+
|
|
416
|
+
| Param | Type | Description |
|
|
417
|
+
| --- | --- | --- |
|
|
418
|
+
| options | [<code>InstancedSpriteOptions</code>](#InstancedSpriteOptions) | 初始化配置项 |
|
|
419
|
+
|
|
377
420
|
<a name="InstancedSpriteCollection+remove"></a>
|
|
378
421
|
|
|
379
422
|
### instancedSpriteCollection.remove(sprite) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
@@ -385,6 +428,23 @@ InstancedSprite实例数量
|
|
|
385
428
|
| --- | --- |
|
|
386
429
|
| sprite | [<code>InstancedSprite</code>](#InstancedSprite) |
|
|
387
430
|
|
|
431
|
+
<a name="InstancedSpriteCollection+clear"></a>
|
|
432
|
+
|
|
433
|
+
### instancedSpriteCollection.clear() ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
434
|
+
移除所有InstancedSprite,并清空所有Mesh的实例数据(Mesh与图集保留以便复用)
|
|
435
|
+
|
|
436
|
+
**Kind**: instance method of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
437
|
+
<a name="InstancedSpriteCollection+reserve"></a>
|
|
438
|
+
|
|
439
|
+
### instancedSpriteCollection.reserve(capacity) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
440
|
+
预分配所有Mesh的容量,避免后续动态扩容
|
|
441
|
+
|
|
442
|
+
**Kind**: instance method of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
443
|
+
|
|
444
|
+
| Param | Type | Description |
|
|
445
|
+
| --- | --- | --- |
|
|
446
|
+
| capacity | <code>number</code> | 需要预留的实例数量 |
|
|
447
|
+
|
|
388
448
|
<a name="InstancedSpriteCollection+forEach"></a>
|
|
389
449
|
|
|
390
450
|
### instancedSpriteCollection.forEach(callback) ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
@@ -408,6 +468,21 @@ Computes intersection points between a casted ray and this sprite.
|
|
|
408
468
|
| raycaster | <code>Raycaster</code> | The raycaster. |
|
|
409
469
|
| intersects | <code>Array.<Object></code> | The target array that holds the intersection points. |
|
|
410
470
|
|
|
471
|
+
<a name="InstancedSpriteCollection+dispose"></a>
|
|
472
|
+
|
|
473
|
+
### instancedSpriteCollection.dispose() ⇒ [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
474
|
+
释放所有 GPU 资源(几何体、材质、图集纹理),并移除所有子 Mesh
|
|
475
|
+
|
|
476
|
+
**Kind**: instance method of [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection)
|
|
477
|
+
<a name="BillboardCollection"></a>
|
|
478
|
+
|
|
479
|
+
## BillboardCollection
|
|
480
|
+
**Kind**: global class
|
|
481
|
+
<a name="new_BillboardCollection_new"></a>
|
|
482
|
+
|
|
483
|
+
### new BillboardCollection()
|
|
484
|
+
InstancedSpriteCollection 的别名。
|
|
485
|
+
|
|
411
486
|
<a name="InstancedSpriteMaterial"></a>
|
|
412
487
|
|
|
413
488
|
## InstancedSpriteMaterial ⇐ <code>ShaderMaterial</code>
|
|
@@ -421,24 +496,39 @@ InstancedSprite 材质类,以attribute形式传入InstancedSprite对象实例
|
|
|
421
496
|
图片纹理
|
|
422
497
|
|
|
423
498
|
**Kind**: instance property of [<code>InstancedSpriteMaterial</code>](#InstancedSpriteMaterial)
|
|
499
|
+
<a name="BillboardMaterial"></a>
|
|
500
|
+
|
|
501
|
+
## BillboardMaterial
|
|
502
|
+
**Kind**: global class
|
|
503
|
+
<a name="new_BillboardMaterial_new"></a>
|
|
504
|
+
|
|
505
|
+
### new BillboardMaterial()
|
|
506
|
+
InstancedSpriteMaterial 的别名。
|
|
507
|
+
|
|
424
508
|
<a name="InstancedSpriteMesh"></a>
|
|
425
509
|
|
|
426
510
|
## InstancedSpriteMesh ⇐ <code>Mesh</code>
|
|
427
511
|
InstancedSpriteMesh类,基于InstancedBufferGeometry实现的高性能InstancedSprite渲染组件
|
|
428
512
|
|
|
513
|
+
一张图集纹理对应一个 InstancedSpriteMesh,所有使用该图集的 Sprite 由其统一绘制
|
|
514
|
+
|
|
429
515
|
**Kind**: global class
|
|
430
516
|
**Extends**: <code>Mesh</code>
|
|
431
517
|
|
|
432
518
|
* [InstancedSpriteMesh](#InstancedSpriteMesh) ⇐ <code>Mesh</code>
|
|
433
519
|
* [new InstancedSpriteMesh(collection, texture)](#new_InstancedSpriteMesh_new)
|
|
434
520
|
* [.type](#InstancedSpriteMesh+type) : <code>string</code>
|
|
521
|
+
* [.frustumCulled](#InstancedSpriteMesh+frustumCulled) : <code>boolean</code>
|
|
435
522
|
* [.isInstancedSpriteMesh](#InstancedSpriteMesh+isInstancedSpriteMesh) : <code>boolean</code>
|
|
436
523
|
* [.depthTest](#InstancedSpriteMesh+depthTest) : <code>boolean</code>
|
|
524
|
+
* [.depthWrite](#InstancedSpriteMesh+depthWrite) : <code>boolean</code>
|
|
437
525
|
* [.instancedSprites](#InstancedSpriteMesh+instancedSprites) : [<code>Array.<InstancedSprite></code>](#InstancedSprite)
|
|
526
|
+
* [.reserve(capacity)](#InstancedSpriteMesh+reserve) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
438
527
|
* [.add(sprite)](#InstancedSpriteMesh+add) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
439
528
|
* [.remove(sprite)](#InstancedSpriteMesh+remove) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
440
529
|
* [.clear()](#InstancedSpriteMesh+clear) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
441
530
|
* [.raycast(raycaster, intersects)](#InstancedSpriteMesh+raycast)
|
|
531
|
+
* [.dispose()](#InstancedSpriteMesh+dispose)
|
|
442
532
|
|
|
443
533
|
<a name="new_InstancedSpriteMesh_new"></a>
|
|
444
534
|
|
|
@@ -447,7 +537,7 @@ InstancedSpriteMesh类,基于InstancedBufferGeometry实现的高性能Instance
|
|
|
447
537
|
| Param | Type | Description |
|
|
448
538
|
| --- | --- | --- |
|
|
449
539
|
| collection | [<code>InstancedSpriteCollection</code>](#InstancedSpriteCollection) | 所属的InstancedSpriteCollection实例,必填 |
|
|
450
|
-
| texture | <code>Texture</code> |
|
|
540
|
+
| texture | <code>Texture</code> | 图集纹理,必填 |
|
|
451
541
|
|
|
452
542
|
<a name="InstancedSpriteMesh+type"></a>
|
|
453
543
|
|
|
@@ -456,6 +546,13 @@ InstancedSpriteMesh类,基于InstancedBufferGeometry实现的高性能Instance
|
|
|
456
546
|
|
|
457
547
|
**Kind**: instance property of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
458
548
|
**Read only**: true
|
|
549
|
+
<a name="InstancedSpriteMesh+frustumCulled"></a>
|
|
550
|
+
|
|
551
|
+
### instancedSpriteMesh.frustumCulled : <code>boolean</code>
|
|
552
|
+
实例化几何体的包围球基于单位四边形(位于原点),不包含实例位置,视锥剔除会把远离原点的实例整批误剔除,因此禁用
|
|
553
|
+
|
|
554
|
+
**Kind**: instance property of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
555
|
+
**Default**: <code>false</code>
|
|
459
556
|
<a name="InstancedSpriteMesh+isInstancedSpriteMesh"></a>
|
|
460
557
|
|
|
461
558
|
### instancedSpriteMesh.isInstancedSpriteMesh : <code>boolean</code>
|
|
@@ -468,6 +565,13 @@ InstancedSpriteMesh对象标识
|
|
|
468
565
|
### instancedSpriteMesh.depthTest : <code>boolean</code>
|
|
469
566
|
深度测试开关,默认为true,开启后会进行深度测试以正确处理遮挡关系,但可能会有性能影响;如果关闭则所有InstancedSprite都会被渲染在最前面,适合需要始终显示的UI元素等场景
|
|
470
567
|
|
|
568
|
+
**Kind**: instance property of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
569
|
+
**Default**: <code>true</code>
|
|
570
|
+
<a name="InstancedSpriteMesh+depthWrite"></a>
|
|
571
|
+
|
|
572
|
+
### instancedSpriteMesh.depthWrite : <code>boolean</code>
|
|
573
|
+
深度写入开关,默认为true;多个半透明 Sprite 重叠时,开启深度写入可能导致排序瑕疵(后方 Sprite 被错误遮挡),关闭可缓解,适合半透明标签/粒子等场景
|
|
574
|
+
|
|
471
575
|
**Kind**: instance property of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
472
576
|
**Default**: <code>true</code>
|
|
473
577
|
<a name="InstancedSpriteMesh+instancedSprites"></a>
|
|
@@ -477,6 +581,17 @@ InstancedSprite对象数组
|
|
|
477
581
|
|
|
478
582
|
**Kind**: instance property of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
479
583
|
**Read only**: true
|
|
584
|
+
<a name="InstancedSpriteMesh+reserve"></a>
|
|
585
|
+
|
|
586
|
+
### instancedSpriteMesh.reserve(capacity) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
587
|
+
预分配容量,避免后续动态扩容(不改变当前实际绘制的实例数量)
|
|
588
|
+
|
|
589
|
+
**Kind**: instance method of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
590
|
+
|
|
591
|
+
| Param | Type | Description |
|
|
592
|
+
| --- | --- | --- |
|
|
593
|
+
| capacity | <code>number</code> | 需要预留的实例数量 |
|
|
594
|
+
|
|
480
595
|
<a name="InstancedSpriteMesh+add"></a>
|
|
481
596
|
|
|
482
597
|
### instancedSpriteMesh.add(sprite) ⇒ [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
@@ -517,6 +632,21 @@ Computes intersection points between a casted ray and this sprite.
|
|
|
517
632
|
| raycaster | <code>Raycaster</code> | The raycaster. |
|
|
518
633
|
| intersects | <code>Array.<Object></code> | The target array that holds the intersection points. |
|
|
519
634
|
|
|
635
|
+
<a name="InstancedSpriteMesh+dispose"></a>
|
|
636
|
+
|
|
637
|
+
### instancedSpriteMesh.dispose()
|
|
638
|
+
释放 GPU 资源
|
|
639
|
+
|
|
640
|
+
**Kind**: instance method of [<code>InstancedSpriteMesh</code>](#InstancedSpriteMesh)
|
|
641
|
+
<a name="BillboardMesh"></a>
|
|
642
|
+
|
|
643
|
+
## BillboardMesh
|
|
644
|
+
**Kind**: global class
|
|
645
|
+
<a name="new_BillboardMesh_new"></a>
|
|
646
|
+
|
|
647
|
+
### new BillboardMesh()
|
|
648
|
+
InstancedSpriteMesh 的别名。
|
|
649
|
+
|
|
520
650
|
<a name="InstancedSpriteNodeMaterial"></a>
|
|
521
651
|
|
|
522
652
|
## InstancedSpriteNodeMaterial ⇐ <code>NodeMaterial</code>
|
|
@@ -535,6 +665,79 @@ InstancedSpriteNodeMaterial 材质类,基于 Three.js TSL (Three Shading Langu
|
|
|
535
665
|
图片纹理
|
|
536
666
|
|
|
537
667
|
**Kind**: instance property of [<code>InstancedSpriteNodeMaterial</code>](#InstancedSpriteNodeMaterial)
|
|
668
|
+
<a name="BillboardNodeMaterial"></a>
|
|
669
|
+
|
|
670
|
+
## BillboardNodeMaterial
|
|
671
|
+
**Kind**: global class
|
|
672
|
+
<a name="new_BillboardNodeMaterial_new"></a>
|
|
673
|
+
|
|
674
|
+
### new BillboardNodeMaterial()
|
|
675
|
+
InstancedSpriteNodeMaterial 的别名。
|
|
676
|
+
|
|
677
|
+
<a name="TextureAtlas"></a>
|
|
678
|
+
|
|
679
|
+
## TextureAtlas
|
|
680
|
+
纹理图集,将多张图片按行(shelf)打包进一张 Canvas 纹理,用于合并 draw call
|
|
681
|
+
|
|
682
|
+
**Kind**: global class
|
|
683
|
+
|
|
684
|
+
* [TextureAtlas](#TextureAtlas)
|
|
685
|
+
* [new TextureAtlas([options])](#new_TextureAtlas_new)
|
|
686
|
+
* [.add(source)](#TextureAtlas+add) ⇒ <code>Object</code> \| <code>null</code>
|
|
687
|
+
* [.getRect(source)](#TextureAtlas+getRect) ⇒ <code>Object</code> \| <code>undefined</code>
|
|
688
|
+
* [.grow()](#TextureAtlas+grow) ⇒ <code>boolean</code>
|
|
689
|
+
* [.getUvRect(rect)](#TextureAtlas+getUvRect) ⇒ <code>Array.<number></code>
|
|
690
|
+
|
|
691
|
+
<a name="new_TextureAtlas_new"></a>
|
|
692
|
+
|
|
693
|
+
### new TextureAtlas([options])
|
|
694
|
+
|
|
695
|
+
| Param | Type | Default | Description |
|
|
696
|
+
| --- | --- | --- | --- |
|
|
697
|
+
| [options] | <code>object</code> | | |
|
|
698
|
+
| [options.initialSize] | <code>number</code> | <code>1024</code> | 初始边长(正方形,单位像素) |
|
|
699
|
+
| [options.maxSize] | <code>number</code> | <code>8192</code> | 最大边长,自动扩容到该值后不再增大 |
|
|
700
|
+
| [options.padding] | <code>number</code> | <code>2</code> | 子图间距,防止线性过滤时边缘渗色 |
|
|
701
|
+
|
|
702
|
+
<a name="TextureAtlas+add"></a>
|
|
703
|
+
|
|
704
|
+
### textureAtlas.add(source) ⇒ <code>Object</code> \| <code>null</code>
|
|
705
|
+
将图片加入图集,返回其像素矩形;已加入过则返回缓存;图集整体已满则返回null
|
|
706
|
+
|
|
707
|
+
**Kind**: instance method of [<code>TextureAtlas</code>](#TextureAtlas)
|
|
708
|
+
|
|
709
|
+
| Param | Type |
|
|
710
|
+
| --- | --- |
|
|
711
|
+
| source | <code>HTMLImageElement</code> \| <code>HTMLCanvasElement</code> |
|
|
712
|
+
|
|
713
|
+
<a name="TextureAtlas+getRect"></a>
|
|
714
|
+
|
|
715
|
+
### textureAtlas.getRect(source) ⇒ <code>Object</code> \| <code>undefined</code>
|
|
716
|
+
获取图片已分配的像素矩形
|
|
717
|
+
|
|
718
|
+
**Kind**: instance method of [<code>TextureAtlas</code>](#TextureAtlas)
|
|
719
|
+
|
|
720
|
+
| Param | Type |
|
|
721
|
+
| --- | --- |
|
|
722
|
+
| source | <code>HTMLImageElement</code> \| <code>HTMLCanvasElement</code> |
|
|
723
|
+
|
|
724
|
+
<a name="TextureAtlas+grow"></a>
|
|
725
|
+
|
|
726
|
+
### textureAtlas.grow() ⇒ <code>boolean</code>
|
|
727
|
+
扩容图集(边长翻倍),成功返回true;已达最大尺寸返回false
|
|
728
|
+
|
|
729
|
+
**Kind**: instance method of [<code>TextureAtlas</code>](#TextureAtlas)
|
|
730
|
+
<a name="TextureAtlas+getUvRect"></a>
|
|
731
|
+
|
|
732
|
+
### textureAtlas.getUvRect(rect) ⇒ <code>Array.<number></code>
|
|
733
|
+
将像素矩形转为归一化 UV(uOffset, vOffset, uScale, vScale)
|
|
734
|
+
|
|
735
|
+
**Kind**: instance method of [<code>TextureAtlas</code>](#TextureAtlas)
|
|
736
|
+
|
|
737
|
+
| Param | Type |
|
|
738
|
+
| --- | --- |
|
|
739
|
+
| rect | <code>Object</code> |
|
|
740
|
+
|
|
538
741
|
<a name="imageLoader"></a>
|
|
539
742
|
|
|
540
743
|
## imageLoader
|
package/README.md
CHANGED
|
@@ -1,55 +1,146 @@
|
|
|
1
|
-
# InstancedSprite
|
|
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
|
-
|
|
1
|
+
# InstancedSprite
|
|
2
|
+
|
|
3
|
+
Three.js 自带的 `Sprite` 不支持 GPU 实例化渲染。当场景中需要同时展示大量标签、图标或提示时,逐个绘制 `Sprite` 会产生大量 draw call,导致帧率明显下降。
|
|
4
|
+
|
|
5
|
+
`InstancedSprite` 基于 `InstancedBufferGeometry` + 自定义 `ShaderMaterial`(或 TSL `NodeMaterial`)实现实例化渲染。**所有 Sprite 的图片打包进纹理图集,合并为极少数 draw call**,极大提升大批量标签的渲染效率。
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- 🚀 **GPU 实例化**:基于 `InstancedBufferGeometry`,数千个 Sprite 仅需一次 draw call
|
|
10
|
+
- 🏷️ **纹理图集合批**:不同图片打包进同一图集,一个图集(一个 Mesh)一次 draw call;图集满自动新建
|
|
11
|
+
- ✏️ **属性自动同步**:直接修改 Sprite 的 `position` / `rotation` / `scale` / `color` 等属性,每帧 `update()` 时通过脏检查自动上传至 GPU,无需手动刷新
|
|
12
|
+
- 🎯 **射线拾取**:内置射线检测,可直接用 `Raycaster` 拾取到具体的 `InstancedSprite` 实例
|
|
13
|
+
- 🖼️ **像素级透明**:片元着色器自动丢弃完全透明的像素
|
|
14
|
+
- 🎨 **双渲染后端**:同时支持 WebGL(GLSL `ShaderMaterial`)与 WebGPU(TSL `NodeMaterial`)
|
|
15
|
+
- 📏 **动态扩容**:实例缓冲区按需自动扩容,实例数量无硬性上限
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @lijuhong1981/three.instancedsprite
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
依赖 `three`(`>= 0.171.0`)。若使用 WebGPU / TSL 材质,需从 `three/webgpu` 引入相关构建。
|
|
24
|
+
|
|
25
|
+
## 使用
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import * as THREE from "three";
|
|
29
|
+
import { InstancedSpriteCollection } from "@lijuhong1981/three.instancedsprite";
|
|
30
|
+
|
|
31
|
+
// 初始化(继承自 Object3D,直接加入场景)
|
|
32
|
+
const collection = new InstancedSpriteCollection();
|
|
33
|
+
scene.add(collection);
|
|
34
|
+
|
|
35
|
+
// 若使用 WebGPURenderer,通过 useNodeMaterial 启用 TSL 的 NodeMaterial
|
|
36
|
+
// const collection = new InstancedSpriteCollection({ useNodeMaterial: true });
|
|
37
|
+
|
|
38
|
+
// 图集可配置(初始/最大边长、子图间距),默认自动扩容到 8192
|
|
39
|
+
// const collection = new InstancedSpriteCollection({ maxSize: 4096 });
|
|
40
|
+
|
|
41
|
+
// 每帧更新:内部做脏检查,把发生变化的属性同步到 GPU
|
|
42
|
+
const onAnimate = () => {
|
|
43
|
+
window.requestAnimationFrame(onAnimate);
|
|
44
|
+
collection.update();
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// 添加一个 Sprite
|
|
48
|
+
const sprite = collection.add({
|
|
49
|
+
position: [100, 100, 100], // 位置(世界空间)
|
|
50
|
+
rotation: 0, // 旋转(弧度)
|
|
51
|
+
scale: 1.0, // 缩放
|
|
52
|
+
sizeAttenuation: false, // 尺寸是否跟随相机深度变化(默认 true)
|
|
53
|
+
center: [0.5, 0], // 中心锚点(0-1,默认 (0.5, 0.5))
|
|
54
|
+
color: 0xff0000, // 颜色(默认 0xffffff)
|
|
55
|
+
opacity: 0.5, // 不透明度(0-1,默认 1)
|
|
56
|
+
image: './res/icon.png', // 图片地址,相同 image 会合并到同一个 Mesh 一次渲染
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 运行时修改属性(无需手动刷新,update() 会自动同步)
|
|
60
|
+
sprite.position.set(200, 100, 0);
|
|
61
|
+
sprite.color.set(0x00ff00);
|
|
62
|
+
sprite.show = false; // 隐藏(等同于 sprite.visible)
|
|
63
|
+
|
|
64
|
+
// 移除
|
|
65
|
+
sprite.remove();
|
|
66
|
+
// 或
|
|
67
|
+
collection.remove(sprite);
|
|
68
|
+
|
|
69
|
+
// 清空所有 Sprite
|
|
70
|
+
collection.clear();
|
|
71
|
+
|
|
72
|
+
// 射线检测
|
|
73
|
+
const ndc = new THREE.Vector2(/* ... */);
|
|
74
|
+
raycaster.setFromCamera(ndc, camera);
|
|
75
|
+
const intersects = raycaster.intersectObject(collection);
|
|
76
|
+
if (intersects.length > 0) {
|
|
77
|
+
const pickedSprite = intersects[0].object; // 拾取到的 InstancedSprite
|
|
78
|
+
const instanceId = intersects[0].instanceId; // 实例索引
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Billboard 别名
|
|
83
|
+
|
|
84
|
+
所有 `InstancedSprite*` 类都有对应的 `Billboard*` 别名导出,语义上表示「始终面向相机的广告牌/标签」,用法完全一致:
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
import { BillboardCollection, Billboard } from "@lijuhong1981/three.instancedsprite";
|
|
88
|
+
|
|
89
|
+
// BillboardCollection === InstancedSpriteCollection
|
|
90
|
+
const collection = new BillboardCollection();
|
|
91
|
+
scene.add(collection);
|
|
92
|
+
|
|
93
|
+
// Billboard === InstancedSprite
|
|
94
|
+
const billboard = collection.add({ image: './res/icon.png', position: [0, 0, 0] });
|
|
95
|
+
console.log(billboard instanceof Billboard); // true
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 主要 API
|
|
99
|
+
|
|
100
|
+
| 类 | 说明 |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| `InstancedSpriteCollection` | 继承自 `Object3D`,批量管理所有 Sprite;使用纹理图集合并 draw call |
|
|
103
|
+
| `InstancedSprite` | 数据模型类,保存单个 Sprite 的全部属性;**不继承 `Object3D`**,不能直接加入 Scene,由 Collection 统一渲染 |
|
|
104
|
+
| `InstancedSpriteMesh` | 继承自 `Mesh`,基于 `InstancedBufferGeometry`,一张图集对应一个 Mesh,由其统一绘制 |
|
|
105
|
+
| `InstancedSpriteMaterial` | 继承自 `ShaderMaterial`,以 instanced attribute 形式接收每个 Sprite 的属性(WebGL) |
|
|
106
|
+
| `InstancedSpriteNodeMaterial` | 继承自 `NodeMaterial`,基于 TSL 实现,功能与 `InstancedSpriteMaterial` 一致(WebGPU) |
|
|
107
|
+
|
|
108
|
+
> 以上每个类都有对应的 `Billboard*` 别名导出(如 `BillboardCollection`、`Billboard`),语义上表示「始终面向相机的广告牌/标签」。
|
|
109
|
+
|
|
110
|
+
### InstancedSpriteCollection
|
|
111
|
+
|
|
112
|
+
- `add(options)` → `InstancedSprite`:添加并返回一个 Sprite
|
|
113
|
+
- `remove(sprite)`:移除指定 Sprite
|
|
114
|
+
- `clear()`:移除所有 Sprite
|
|
115
|
+
- `get(index)` / `getByUuid(uuid)`:按索引 / uuid 获取
|
|
116
|
+
- `forEach(callback)`:遍历所有 Sprite
|
|
117
|
+
- `update()`:每帧调用,同步属性变化
|
|
118
|
+
- `raycast(raycaster, intersects)`:射线拾取
|
|
119
|
+
- `instancedSprites`:Sprite 数组(只读);`size`:数量(只读)
|
|
120
|
+
- `depthTest`:深度测试开关(默认 `true`;关闭后所有 Sprite 始终渲染在最前,适合 UI 元素)
|
|
121
|
+
|
|
122
|
+
### InstancedSprite 属性
|
|
123
|
+
|
|
124
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
125
|
+
| --- | --- | --- | --- |
|
|
126
|
+
| `position` | `Vector3` | `(0, 0, 0)` | 世界坐标位置 |
|
|
127
|
+
| `scale` | `number` | `1` | 缩放 |
|
|
128
|
+
| `rotation` | `number` | `0` | 旋转(弧度);可用 `rotationDegrees` 以角度读写 |
|
|
129
|
+
| `sizeAttenuation` | `boolean` | `true` | 尺寸是否跟随相机深度变化 |
|
|
130
|
+
| `center` | `Vector2` | `(0.5, 0.5)` | 锚点中心(0-1) |
|
|
131
|
+
| `color` | `Color` | `0xffffff` | 颜色 |
|
|
132
|
+
| `opacity` | `number` | `1` | 不透明度(0-1) |
|
|
133
|
+
| `show` / `visible` | `boolean` | `true` | 是否显示 |
|
|
134
|
+
| `image` | `string \| HTMLImageElement \| HTMLCanvasElement` | - | 图片资源 |
|
|
135
|
+
| `imageSize` / `imageWidth` / `imageHeight` | - | - | 图片尺寸,图片加载完成后可用(只读) |
|
|
136
|
+
| `userData` | `object` | `{}` | 用户自定义数据 |
|
|
137
|
+
| `uuid` | `string` | - | 唯一标识(只读) |
|
|
138
|
+
|
|
139
|
+
## 工作原理
|
|
140
|
+
|
|
141
|
+
1. `InstancedSpriteCollection.add()` 创建 `InstancedSprite` 数据对象,并将其 `image` 打包进纹理图集(同一图片只打包一次)。
|
|
142
|
+
2. `InstancedSpriteMesh` 持有 `InstancedBufferGeometry`,为每个实例分配一组 instanced attribute(位置+显示、锚点+尺寸、缩放+旋转+衰减、颜色+透明度、拾取颜色)。
|
|
143
|
+
3. 顶点着色器根据实例属性计算 billboard 位置(对齐、旋转、透视缩放),片元着色器采样纹理并应用颜色 / 透明度。
|
|
144
|
+
4. 每帧调用 `update()`:仅当属性实际发生变化(脏检查)时才更新对应缓冲区,减少 CPU→GPU 传输开销;缓冲区按需自动扩容。
|
|
145
|
+
|
|
146
|
+
## [API 文档](./API.md)
|
package/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export * from "./src/InstancedSprite.js";
|
|
2
|
-
export * from "./src/InstancedSpriteCollection.js";
|
|
3
|
-
export * from "./src/InstancedSpriteMaterial.js";
|
|
4
|
-
export * from "./src/InstancedSpriteMesh.js";
|
|
5
|
-
export * from "./src/InstancedSpriteNodeMaterial.js";
|
|
1
|
+
export * from "./src/InstancedSprite.js";
|
|
2
|
+
export * from "./src/InstancedSpriteCollection.js";
|
|
3
|
+
export * from "./src/InstancedSpriteMaterial.js";
|
|
4
|
+
export * from "./src/InstancedSpriteMesh.js";
|
|
5
|
+
export * from "./src/InstancedSpriteNodeMaterial.js";
|
|
6
|
+
export * from "./src/TextureAtlas.js";
|
package/package.json
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lijuhong1981/three.instancedsprite",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "index.js",
|
|
7
7
|
"main": "index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js",
|
|
10
|
+
"src/",
|
|
11
|
+
"API.md"
|
|
12
|
+
],
|
|
8
13
|
"publishConfig": {
|
|
9
14
|
"access": "public"
|
|
10
15
|
},
|
|
11
16
|
"scripts": {
|
|
12
17
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
13
|
-
"docs": "jsdoc2md --files src/*.js > API.md"
|
|
18
|
+
"docs": "jsdoc2md --files src/*.js > API.md",
|
|
19
|
+
"dev": "vite test"
|
|
14
20
|
},
|
|
15
21
|
"repository": {
|
|
16
22
|
"type": "git",
|
|
@@ -36,6 +42,7 @@
|
|
|
36
42
|
"three": ">=0.171.0"
|
|
37
43
|
},
|
|
38
44
|
"devDependencies": {
|
|
39
|
-
"jsdoc-to-markdown": "^9.1.3"
|
|
45
|
+
"jsdoc-to-markdown": "^9.1.3",
|
|
46
|
+
"vite": "^8.3.3"
|
|
40
47
|
}
|
|
41
|
-
}
|
|
48
|
+
}
|
package/src/InstancedSprite.js
CHANGED
|
@@ -2,7 +2,7 @@ import Check from "@lijuhong1981/jscheck/src/Check.js";
|
|
|
2
2
|
import ImageLoader from "@lijuhong1981/jsload/src/ImageLoader.js";
|
|
3
3
|
import { Loader } from "@lijuhong1981/jsload/src/Loader.js";
|
|
4
4
|
import setValues from "@lijuhong1981/three.utils/src/setValues.js";
|
|
5
|
-
import { Color, InstancedBufferGeometry, MathUtils, Matrix4, Triangle, Vector2, Vector3 } from "three";
|
|
5
|
+
import { Color, InstancedBufferGeometry, MathUtils, Matrix4, Triangle, Vector2, Vector3, Vector4 } from "three";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @import InstancedSpriteCollection from "./InstancedSpriteCollection.js";
|
|
@@ -169,6 +169,13 @@ class InstancedSprite {
|
|
|
169
169
|
*/
|
|
170
170
|
this.imageSize = new Vector2(0, 0);
|
|
171
171
|
this._imageSize = new Vector2(0, 0);
|
|
172
|
+
/**
|
|
173
|
+
* 图集UV区域(x: u偏移, y: v偏移, z: u缩放, w: v缩放),非图集模式默认为(0,0,1,1)即整张纹理
|
|
174
|
+
* @type {Vector4}
|
|
175
|
+
* @ignore
|
|
176
|
+
*/
|
|
177
|
+
this.uvRect = new Vector4(0, 0, 1, 1);
|
|
178
|
+
this._uvRect = new Vector4(0, 0, 1, 1);
|
|
172
179
|
this._image = null;
|
|
173
180
|
/**
|
|
174
181
|
* 拾取颜色,用于GPU拾取,由Picking管理器设置和使用,用户无需关心
|
|
@@ -366,3 +373,9 @@ class InstancedSprite {
|
|
|
366
373
|
|
|
367
374
|
export default InstancedSprite;
|
|
368
375
|
export { InstancedSprite };
|
|
376
|
+
/**
|
|
377
|
+
* InstancedSprite 的别名(广告牌语义)。
|
|
378
|
+
* @class
|
|
379
|
+
* @name Billboard
|
|
380
|
+
*/
|
|
381
|
+
export const Billboard = InstancedSprite;
|