@newkrok/three-particles 2.10.4 → 2.11.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/dist/index.js CHANGED
@@ -170,6 +170,11 @@ var ForceFieldType = /* @__PURE__ */ ((ForceFieldType2) => {
170
170
  ForceFieldType2["DIRECTIONAL"] = "DIRECTIONAL";
171
171
  return ForceFieldType2;
172
172
  })(ForceFieldType || {});
173
+ var RendererType = /* @__PURE__ */ ((RendererType2) => {
174
+ RendererType2["POINTS"] = "POINTS";
175
+ RendererType2["INSTANCED"] = "INSTANCED";
176
+ return RendererType2;
177
+ })(RendererType || {});
173
178
  var ForceFieldFalloff = /* @__PURE__ */ ((ForceFieldFalloff2) => {
174
179
  ForceFieldFalloff2["NONE"] = "NONE";
175
180
  ForceFieldFalloff2["LINEAR"] = "LINEAR";
@@ -490,6 +495,140 @@ var applyModifiers = ({
490
495
  }
491
496
  };
492
497
 
498
+ // src/js/effects/three-particles/shaders/instanced-particle-fragment-shader.glsl.ts
499
+ var InstancedParticleFragmentShader = `
500
+ uniform sampler2D map;
501
+ uniform float elapsed;
502
+ uniform float fps;
503
+ uniform bool useFPSForFrameIndex;
504
+ uniform vec2 tiles;
505
+ uniform bool discardBackgroundColor;
506
+ uniform vec3 backgroundColor;
507
+ uniform float backgroundColorTolerance;
508
+
509
+ varying vec2 vUv;
510
+ varying vec4 vColor;
511
+ varying float vLifetime;
512
+ varying float vStartLifetime;
513
+ varying float vStartFrame;
514
+ varying float vRotation;
515
+
516
+ #include <common>
517
+ #include <logdepthbuf_pars_fragment>
518
+
519
+ void main()
520
+ {
521
+ gl_FragColor = vColor;
522
+
523
+ // Rotate UV around centre (matches Points renderer behaviour)
524
+ vec2 center = vec2(0.5);
525
+ vec2 centeredPoint = vUv - center;
526
+
527
+ mat2 rotation = mat2(
528
+ cos(vRotation), sin(vRotation),
529
+ -sin(vRotation), cos(vRotation)
530
+ );
531
+
532
+ centeredPoint = rotation * centeredPoint;
533
+ vec2 centeredMiddlePoint = centeredPoint + center;
534
+
535
+ // Discard pixels outside the inscribed circle
536
+ float dist = distance(centeredMiddlePoint, center);
537
+ if (dist > 0.5) discard;
538
+
539
+ float frameIndex = round(vStartFrame) + (
540
+ useFPSForFrameIndex == true
541
+ ? fps == 0.0
542
+ ? 0.0
543
+ : max((vLifetime / 1000.0) * fps, 0.0)
544
+ : max(min(floor(min(vLifetime / vStartLifetime, 1.0) * (tiles.x * tiles.y)), tiles.x * tiles.y - 1.0), 0.0)
545
+ );
546
+
547
+ float spriteXIndex = floor(mod(frameIndex, tiles.x));
548
+ float spriteYIndex = floor(mod(frameIndex / tiles.x, tiles.y));
549
+
550
+ vec2 uvPoint = vec2(
551
+ centeredMiddlePoint.x / tiles.x + spriteXIndex / tiles.x,
552
+ centeredMiddlePoint.y / tiles.y + spriteYIndex / tiles.y
553
+ );
554
+
555
+ vec4 rotatedTexture = texture2D(map, uvPoint);
556
+
557
+ gl_FragColor = gl_FragColor * rotatedTexture;
558
+
559
+ if (discardBackgroundColor && abs(length(rotatedTexture.rgb - backgroundColor.rgb)) < backgroundColorTolerance) discard;
560
+
561
+ #include <logdepthbuf_fragment>
562
+ }
563
+ `;
564
+ var instanced_particle_fragment_shader_glsl_default = InstancedParticleFragmentShader;
565
+
566
+ // src/js/effects/three-particles/shaders/instanced-particle-vertex-shader.glsl.ts
567
+ var InstancedParticleVertexShader = `
568
+ attribute float instanceSize;
569
+ attribute float instanceColorR;
570
+ attribute float instanceColorG;
571
+ attribute float instanceColorB;
572
+ attribute float instanceColorA;
573
+ attribute float instanceLifetime;
574
+ attribute float instanceStartLifetime;
575
+ attribute float instanceRotation;
576
+ attribute float instanceStartFrame;
577
+ attribute vec3 instanceOffset;
578
+
579
+ uniform float viewportHeight;
580
+
581
+ varying vec2 vUv;
582
+ varying vec4 vColor;
583
+ varying float vLifetime;
584
+ varying float vStartLifetime;
585
+ varying float vStartFrame;
586
+ varying float vRotation;
587
+
588
+ #include <common>
589
+ #include <logdepthbuf_pars_vertex>
590
+
591
+ void main()
592
+ {
593
+ vColor = vec4(instanceColorR, instanceColorG, instanceColorB, instanceColorA);
594
+ vLifetime = instanceLifetime;
595
+ vStartLifetime = instanceStartLifetime;
596
+ vStartFrame = instanceStartFrame;
597
+ vRotation = instanceRotation;
598
+
599
+ vec4 mvPosition = modelViewMatrix * vec4(instanceOffset, 1.0);
600
+
601
+ // Match the Points renderer pixel size: gl_PointSize = size * 100.0 / distance.
602
+ // A view-space offset of d produces d * projectionMatrix[1][1] / w * (viewportHeight/2) pixels,
603
+ // where w = -mvPosition.z for perspective. Solving for d so the result equals
604
+ // the gl_PointSize pixel count:
605
+ // d = size * 100.0 / distance
606
+ // * (-mvPosition.z)
607
+ // / (projectionMatrix[1][1] * viewportHeight * 0.5)
608
+ // Since distance \u2248 -mvPosition.z for view-aligned particles the two cancel out,
609
+ // leaving a distance-independent expression. We keep them explicit so particles
610
+ // off the viewing axis still scale correctly.
611
+ float dist = length(mvPosition.xyz);
612
+ float pointSizePx = instanceSize * 100.0 / dist;
613
+ float perspectiveSize = pointSizePx * (-mvPosition.z)
614
+ / (projectionMatrix[1][1] * viewportHeight * 0.5);
615
+
616
+ // Billboard: offset quad vertices in view space (no rotation here;
617
+ // rotation is applied to UVs in the fragment shader to keep behaviour
618
+ // identical to the Points renderer).
619
+ mvPosition.xy += position.xy * perspectiveSize;
620
+
621
+ gl_Position = projectionMatrix * mvPosition;
622
+
623
+ // Pass UV for texture sampling (quad ranges from -0.5..0.5, map to 0..1).
624
+ // Flip Y to match gl_PointCoord convention (Y runs top-to-bottom).
625
+ vUv = vec2(position.x + 0.5, 0.5 - position.y);
626
+
627
+ #include <logdepthbuf_vertex>
628
+ }
629
+ `;
630
+ var instanced_particle_vertex_shader_glsl_default = InstancedParticleVertexShader;
631
+
493
632
  // src/js/effects/three-particles/shaders/particle-system-fragment-shader.glsl.ts
494
633
  var ParticleSystemFragmentShader = `
495
634
  uniform sampler2D map;
@@ -847,7 +986,8 @@ var createFloat32Attributes = ({
847
986
  geometry,
848
987
  propertyName,
849
988
  maxParticles,
850
- factory
989
+ factory,
990
+ instanced
851
991
  }) => {
852
992
  const array = new Float32Array(maxParticles);
853
993
  if (typeof factory === "function") {
@@ -857,7 +997,8 @@ var createFloat32Attributes = ({
857
997
  } else {
858
998
  array.fill(factory);
859
999
  }
860
- geometry.setAttribute(propertyName, new THREE4.BufferAttribute(array, 1));
1000
+ const attr = instanced ? new THREE4.InstancedBufferAttribute(array, 1) : new THREE4.BufferAttribute(array, 1);
1001
+ geometry.setAttribute(propertyName, attr);
861
1002
  };
862
1003
  var calculatePositionAndVelocity = (generalData, { shape, sphere, cone, circle, rectangle, box }, startSpeed, position, velocity) => {
863
1004
  const calculatedStartSpeed = calculateValue(
@@ -1153,41 +1294,59 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1153
1294
  probabilityPassed: false
1154
1295
  }));
1155
1296
  }
1156
- const material = new THREE4.ShaderMaterial({
1157
- uniforms: {
1158
- elapsed: {
1159
- value: 0
1160
- },
1161
- map: {
1162
- value: particleMap
1163
- },
1164
- tiles: {
1165
- value: textureSheetAnimation.tiles
1166
- },
1167
- fps: {
1168
- value: textureSheetAnimation.fps
1169
- },
1170
- useFPSForFrameIndex: {
1171
- value: textureSheetAnimation.timeMode === "FPS" /* FPS */
1172
- },
1173
- backgroundColor: {
1174
- value: renderer.backgroundColor
1175
- },
1176
- discardBackgroundColor: {
1177
- value: renderer.discardBackgroundColor
1178
- },
1179
- backgroundColorTolerance: {
1180
- value: renderer.backgroundColorTolerance
1181
- }
1297
+ const useInstancing = renderer.rendererType === "INSTANCED" /* INSTANCED */;
1298
+ const attr = (name) => useInstancing ? `instance${name.charAt(0).toUpperCase()}${name.slice(1)}` : name;
1299
+ const posAttr = useInstancing ? "instanceOffset" : "position";
1300
+ const sharedUniforms = {
1301
+ elapsed: { value: 0 },
1302
+ map: { value: particleMap },
1303
+ tiles: { value: textureSheetAnimation.tiles },
1304
+ fps: { value: textureSheetAnimation.fps },
1305
+ useFPSForFrameIndex: {
1306
+ value: textureSheetAnimation.timeMode === "FPS" /* FPS */
1182
1307
  },
1183
- vertexShader: particle_system_vertex_shader_glsl_default,
1184
- fragmentShader: particle_system_fragment_shader_glsl_default,
1308
+ backgroundColor: { value: renderer.backgroundColor },
1309
+ discardBackgroundColor: { value: renderer.discardBackgroundColor },
1310
+ backgroundColorTolerance: { value: renderer.backgroundColorTolerance },
1311
+ ...useInstancing ? { viewportHeight: { value: 1 } } : {}
1312
+ };
1313
+ const material = new THREE4.ShaderMaterial({
1314
+ uniforms: sharedUniforms,
1315
+ vertexShader: useInstancing ? instanced_particle_vertex_shader_glsl_default : particle_system_vertex_shader_glsl_default,
1316
+ fragmentShader: useInstancing ? instanced_particle_fragment_shader_glsl_default : particle_system_fragment_shader_glsl_default,
1185
1317
  transparent: renderer.transparent,
1186
1318
  blending: renderer.blending,
1187
1319
  depthTest: renderer.depthTest,
1188
1320
  depthWrite: renderer.depthWrite
1189
1321
  });
1190
- const geometry = new THREE4.BufferGeometry();
1322
+ let geometry;
1323
+ if (useInstancing) {
1324
+ const instancedGeometry = new THREE4.InstancedBufferGeometry();
1325
+ const quadPositions = new Float32Array([
1326
+ -0.5,
1327
+ -0.5,
1328
+ 0,
1329
+ 0.5,
1330
+ -0.5,
1331
+ 0,
1332
+ 0.5,
1333
+ 0.5,
1334
+ 0,
1335
+ -0.5,
1336
+ 0.5,
1337
+ 0
1338
+ ]);
1339
+ const quadIndices = new Uint16Array([0, 1, 2, 0, 2, 3]);
1340
+ instancedGeometry.setAttribute(
1341
+ "position",
1342
+ new THREE4.BufferAttribute(quadPositions, 3)
1343
+ );
1344
+ instancedGeometry.setIndex(new THREE4.BufferAttribute(quadIndices, 1));
1345
+ instancedGeometry.instanceCount = maxParticles;
1346
+ geometry = instancedGeometry;
1347
+ } else {
1348
+ geometry = new THREE4.BufferGeometry();
1349
+ }
1191
1350
  for (let i = 0; i < maxParticles; i++)
1192
1351
  calculatePositionAndVelocity(
1193
1352
  generalData,
@@ -1202,91 +1361,99 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1202
1361
  positionArray[i * 3 + 1] = startPositions[i].y;
1203
1362
  positionArray[i * 3 + 2] = startPositions[i].z;
1204
1363
  }
1205
- geometry.setAttribute(
1206
- "position",
1207
- new THREE4.BufferAttribute(positionArray, 3)
1208
- );
1364
+ const positionAttribute = useInstancing ? new THREE4.InstancedBufferAttribute(positionArray, 3) : new THREE4.BufferAttribute(positionArray, 3);
1365
+ geometry.setAttribute(posAttr, positionAttribute);
1209
1366
  createFloat32Attributes({
1210
1367
  geometry,
1211
- propertyName: "isActive",
1368
+ propertyName: attr("isActive"),
1212
1369
  maxParticles,
1213
- factory: 0
1370
+ factory: 0,
1371
+ instanced: useInstancing
1214
1372
  });
1215
1373
  createFloat32Attributes({
1216
1374
  geometry,
1217
- propertyName: "lifetime",
1375
+ propertyName: attr("lifetime"),
1218
1376
  maxParticles,
1219
- factory: 0
1377
+ factory: 0,
1378
+ instanced: useInstancing
1220
1379
  });
1221
1380
  createFloat32Attributes({
1222
1381
  geometry,
1223
- propertyName: "startLifetime",
1382
+ propertyName: attr("startLifetime"),
1224
1383
  maxParticles,
1225
- factory: () => calculateValue(generalData.particleSystemId, startLifetime, 0) * 1e3
1384
+ factory: () => calculateValue(generalData.particleSystemId, startLifetime, 0) * 1e3,
1385
+ instanced: useInstancing
1226
1386
  });
1227
1387
  createFloat32Attributes({
1228
1388
  geometry,
1229
- propertyName: "startFrame",
1389
+ propertyName: attr("startFrame"),
1230
1390
  maxParticles,
1231
1391
  factory: () => textureSheetAnimation.startFrame ? calculateValue(
1232
1392
  generalData.particleSystemId,
1233
1393
  textureSheetAnimation.startFrame,
1234
1394
  0
1235
- ) : 0
1395
+ ) : 0,
1396
+ instanced: useInstancing
1236
1397
  });
1237
1398
  createFloat32Attributes({
1238
1399
  geometry,
1239
- propertyName: "opacity",
1400
+ propertyName: attr("size"),
1240
1401
  maxParticles,
1241
- factory: () => calculateValue(generalData.particleSystemId, startOpacity, 0)
1402
+ factory: (_, index) => generalData.startValues.startSize[index],
1403
+ instanced: useInstancing
1242
1404
  });
1243
1405
  createFloat32Attributes({
1244
1406
  geometry,
1245
- propertyName: "rotation",
1407
+ propertyName: attr("rotation"),
1246
1408
  maxParticles,
1247
- factory: () => calculateValue(generalData.particleSystemId, startRotation, 0)
1248
- });
1249
- createFloat32Attributes({
1250
- geometry,
1251
- propertyName: "size",
1252
- maxParticles,
1253
- factory: (_, index) => generalData.startValues.startSize[index]
1254
- });
1255
- createFloat32Attributes({
1256
- geometry,
1257
- propertyName: "rotation",
1258
- maxParticles,
1259
- factory: 0
1409
+ factory: 0,
1410
+ instanced: useInstancing
1260
1411
  });
1261
1412
  const colorRandomRatio = Math.random();
1262
1413
  createFloat32Attributes({
1263
1414
  geometry,
1264
- propertyName: "colorR",
1415
+ propertyName: attr("colorR"),
1265
1416
  maxParticles,
1266
- factory: () => startColor.min.r + colorRandomRatio * (startColor.max.r - startColor.min.r)
1417
+ factory: () => startColor.min.r + colorRandomRatio * (startColor.max.r - startColor.min.r),
1418
+ instanced: useInstancing
1267
1419
  });
1268
1420
  createFloat32Attributes({
1269
1421
  geometry,
1270
- propertyName: "colorG",
1422
+ propertyName: attr("colorG"),
1271
1423
  maxParticles,
1272
- factory: () => startColor.min.g + colorRandomRatio * (startColor.max.g - startColor.min.g)
1424
+ factory: () => startColor.min.g + colorRandomRatio * (startColor.max.g - startColor.min.g),
1425
+ instanced: useInstancing
1273
1426
  });
1274
1427
  createFloat32Attributes({
1275
1428
  geometry,
1276
- propertyName: "colorB",
1429
+ propertyName: attr("colorB"),
1277
1430
  maxParticles,
1278
- factory: () => startColor.min.b + colorRandomRatio * (startColor.max.b - startColor.min.b)
1431
+ factory: () => startColor.min.b + colorRandomRatio * (startColor.max.b - startColor.min.b),
1432
+ instanced: useInstancing
1279
1433
  });
1280
1434
  createFloat32Attributes({
1281
1435
  geometry,
1282
- propertyName: "colorA",
1436
+ propertyName: attr("colorA"),
1283
1437
  maxParticles,
1284
- factory: 0
1438
+ factory: 0,
1439
+ instanced: useInstancing
1285
1440
  });
1441
+ const a = geometry.attributes;
1442
+ const aIsActive = a[attr("isActive")];
1443
+ const aColorR = a[attr("colorR")];
1444
+ const aColorG = a[attr("colorG")];
1445
+ const aColorB = a[attr("colorB")];
1446
+ const aColorA = a[attr("colorA")];
1447
+ const aStartFrame = a[attr("startFrame")];
1448
+ const aStartLifetime = a[attr("startLifetime")];
1449
+ const aSize = a[attr("size")];
1450
+ const aRotation = a[attr("rotation")];
1451
+ const aLifetime = a[attr("lifetime")];
1452
+ const aPosition = a[posAttr];
1286
1453
  const deactivateParticle = (particleIndex) => {
1287
- geometry.attributes.isActive.array[particleIndex] = 0;
1288
- geometry.attributes.colorA.array[particleIndex] = 0;
1289
- geometry.attributes.colorA.needsUpdate = true;
1454
+ aIsActive.array[particleIndex] = 0;
1455
+ aColorA.array[particleIndex] = 0;
1456
+ aColorA.needsUpdate = true;
1290
1457
  freeList.push(particleIndex);
1291
1458
  };
1292
1459
  const activateParticle = ({
@@ -1294,52 +1461,52 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1294
1461
  activationTime,
1295
1462
  position
1296
1463
  }) => {
1297
- geometry.attributes.isActive.array[particleIndex] = 1;
1464
+ aIsActive.array[particleIndex] = 1;
1298
1465
  generalData.creationTimes[particleIndex] = activationTime;
1299
1466
  if (generalData.noise.offsets)
1300
1467
  generalData.noise.offsets[particleIndex] = Math.random() * 100;
1301
1468
  const colorRandomRatio2 = Math.random();
1302
- geometry.attributes.colorR.array[particleIndex] = startColor.min.r + colorRandomRatio2 * (startColor.max.r - startColor.min.r);
1303
- geometry.attributes.colorR.needsUpdate = true;
1304
- geometry.attributes.colorG.array[particleIndex] = startColor.min.g + colorRandomRatio2 * (startColor.max.g - startColor.min.g);
1305
- geometry.attributes.colorG.needsUpdate = true;
1306
- geometry.attributes.colorB.array[particleIndex] = startColor.min.b + colorRandomRatio2 * (startColor.max.b - startColor.min.b);
1307
- geometry.attributes.colorB.needsUpdate = true;
1308
- generalData.startValues.startColorR[particleIndex] = geometry.attributes.colorR.array[particleIndex];
1309
- generalData.startValues.startColorG[particleIndex] = geometry.attributes.colorG.array[particleIndex];
1310
- generalData.startValues.startColorB[particleIndex] = geometry.attributes.colorB.array[particleIndex];
1311
- geometry.attributes.startFrame.array[particleIndex] = textureSheetAnimation.startFrame ? calculateValue(
1469
+ aColorR.array[particleIndex] = startColor.min.r + colorRandomRatio2 * (startColor.max.r - startColor.min.r);
1470
+ aColorR.needsUpdate = true;
1471
+ aColorG.array[particleIndex] = startColor.min.g + colorRandomRatio2 * (startColor.max.g - startColor.min.g);
1472
+ aColorG.needsUpdate = true;
1473
+ aColorB.array[particleIndex] = startColor.min.b + colorRandomRatio2 * (startColor.max.b - startColor.min.b);
1474
+ aColorB.needsUpdate = true;
1475
+ generalData.startValues.startColorR[particleIndex] = aColorR.array[particleIndex];
1476
+ generalData.startValues.startColorG[particleIndex] = aColorG.array[particleIndex];
1477
+ generalData.startValues.startColorB[particleIndex] = aColorB.array[particleIndex];
1478
+ aStartFrame.array[particleIndex] = textureSheetAnimation.startFrame ? calculateValue(
1312
1479
  generalData.particleSystemId,
1313
1480
  textureSheetAnimation.startFrame,
1314
1481
  0
1315
1482
  ) : 0;
1316
- geometry.attributes.startFrame.needsUpdate = true;
1317
- geometry.attributes.startLifetime.array[particleIndex] = calculateValue(
1483
+ aStartFrame.needsUpdate = true;
1484
+ aStartLifetime.array[particleIndex] = calculateValue(
1318
1485
  generalData.particleSystemId,
1319
1486
  startLifetime,
1320
1487
  generalData.normalizedLifetimePercentage
1321
1488
  ) * 1e3;
1322
- geometry.attributes.startLifetime.needsUpdate = true;
1489
+ aStartLifetime.needsUpdate = true;
1323
1490
  generalData.startValues.startSize[particleIndex] = calculateValue(
1324
1491
  generalData.particleSystemId,
1325
1492
  startSize,
1326
1493
  generalData.normalizedLifetimePercentage
1327
1494
  );
1328
- geometry.attributes.size.array[particleIndex] = generalData.startValues.startSize[particleIndex];
1329
- geometry.attributes.size.needsUpdate = true;
1495
+ aSize.array[particleIndex] = generalData.startValues.startSize[particleIndex];
1496
+ aSize.needsUpdate = true;
1330
1497
  generalData.startValues.startOpacity[particleIndex] = calculateValue(
1331
1498
  generalData.particleSystemId,
1332
1499
  startOpacity,
1333
1500
  generalData.normalizedLifetimePercentage
1334
1501
  );
1335
- geometry.attributes.colorA.array[particleIndex] = generalData.startValues.startOpacity[particleIndex];
1336
- geometry.attributes.colorA.needsUpdate = true;
1337
- geometry.attributes.rotation.array[particleIndex] = calculateValue(
1502
+ aColorA.array[particleIndex] = generalData.startValues.startOpacity[particleIndex];
1503
+ aColorA.needsUpdate = true;
1504
+ aRotation.array[particleIndex] = calculateValue(
1338
1505
  generalData.particleSystemId,
1339
1506
  startRotation,
1340
1507
  generalData.normalizedLifetimePercentage
1341
1508
  );
1342
- geometry.attributes.rotation.needsUpdate = true;
1509
+ aRotation.needsUpdate = true;
1343
1510
  if (normalizedConfig.rotationOverLifetime.isActive)
1344
1511
  generalData.lifetimeValues.rotationOverLifetime[particleIndex] = THREE4.MathUtils.randFloat(
1345
1512
  normalizedConfig.rotationOverLifetime.min,
@@ -1353,10 +1520,10 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1353
1520
  velocities[particleIndex]
1354
1521
  );
1355
1522
  const positionIndex = Math.floor(particleIndex * 3);
1356
- geometry.attributes.position.array[positionIndex] = position.x + startPositions[particleIndex].x;
1357
- geometry.attributes.position.array[positionIndex + 1] = position.y + startPositions[particleIndex].y;
1358
- geometry.attributes.position.array[positionIndex + 2] = position.z + startPositions[particleIndex].z;
1359
- geometry.attributes.position.needsUpdate = true;
1523
+ aPosition.array[positionIndex] = position.x + startPositions[particleIndex].x;
1524
+ aPosition.array[positionIndex + 1] = position.y + startPositions[particleIndex].y;
1525
+ aPosition.array[positionIndex + 2] = position.z + startPositions[particleIndex].z;
1526
+ aPosition.needsUpdate = true;
1360
1527
  if (generalData.linearVelocityData) {
1361
1528
  generalData.linearVelocityData[particleIndex].speed.set(
1362
1529
  normalizedConfig.velocityOverLifetime.linear.x ? calculateValue(
@@ -1400,13 +1567,13 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1400
1567
  startPositions[particleIndex].z
1401
1568
  );
1402
1569
  }
1403
- geometry.attributes.lifetime.array[particleIndex] = 0;
1404
- geometry.attributes.lifetime.needsUpdate = true;
1570
+ aLifetime.array[particleIndex] = 0;
1571
+ aLifetime.needsUpdate = true;
1405
1572
  applyModifiers({
1406
1573
  delta: 0,
1407
1574
  generalData,
1408
1575
  normalizedConfig,
1409
- attributes: particleSystem.geometry.attributes,
1576
+ attributes: mappedAttributes,
1410
1577
  particleLifetimePercentage: 0,
1411
1578
  particleIndex
1412
1579
  });
@@ -1425,8 +1592,9 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1425
1592
  const cleanupCompletedInstances = (instances) => {
1426
1593
  for (let i = instances.length - 1; i >= 0; i--) {
1427
1594
  const sub = instances[i];
1428
- const points = sub.instance instanceof THREE4.Points ? sub.instance : sub.instance.children[0];
1429
- const isActiveArr = points?.geometry?.attributes?.isActive?.array;
1595
+ const obj3d = sub.instance instanceof THREE4.Points || sub.instance instanceof THREE4.Mesh ? sub.instance : sub.instance.children[0];
1596
+ const geomAttrs = obj3d?.geometry?.attributes;
1597
+ const isActiveArr = geomAttrs ? geomAttrs.isActive?.array ?? geomAttrs.instanceIsActive?.array : void 0;
1430
1598
  if (!isActiveArr) {
1431
1599
  sub.dispose();
1432
1600
  instances.splice(i, 1);
@@ -1462,6 +1630,10 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1462
1630
  ...subConfig.config.transform,
1463
1631
  position: new THREE4.Vector3(position.x, position.y, position.z)
1464
1632
  },
1633
+ renderer: {
1634
+ ...subConfig.config.renderer ?? {},
1635
+ rendererType: renderer.rendererType
1636
+ },
1465
1637
  ...inheritVelocity > 0 ? {
1466
1638
  startSpeed: (typeof subConfig.config.startSpeed === "number" ? subConfig.config.startSpeed : typeof subConfig.config.startSpeed === "object" && subConfig.config.startSpeed !== null && "min" in subConfig.config.startSpeed ? subConfig.config.startSpeed.min ?? 0 : 0) + velocity.length() * inheritVelocity
1467
1639
  } : {}
@@ -1473,12 +1645,31 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1473
1645
  instances.push(subSystem);
1474
1646
  }
1475
1647
  };
1476
- let particleSystem = new THREE4.Points(geometry, material);
1648
+ let particleSystem = useInstancing ? new THREE4.Mesh(geometry, material) : new THREE4.Points(geometry, material);
1649
+ if (useInstancing) {
1650
+ particleSystem.onBeforeRender = (glRenderer) => {
1651
+ const size = glRenderer.getSize(new THREE4.Vector2());
1652
+ sharedUniforms.viewportHeight.value = size.y * glRenderer.getPixelRatio();
1653
+ };
1654
+ }
1477
1655
  particleSystem.position.copy(transform.position);
1478
1656
  particleSystem.rotation.x = THREE4.MathUtils.degToRad(transform.rotation.x);
1479
1657
  particleSystem.rotation.y = THREE4.MathUtils.degToRad(transform.rotation.y);
1480
1658
  particleSystem.rotation.z = THREE4.MathUtils.degToRad(transform.rotation.z);
1481
1659
  particleSystem.scale.copy(transform.scale);
1660
+ const mappedAttributes = {
1661
+ position: aPosition,
1662
+ isActive: aIsActive,
1663
+ lifetime: aLifetime,
1664
+ startLifetime: aStartLifetime,
1665
+ startFrame: aStartFrame,
1666
+ size: aSize,
1667
+ rotation: aRotation,
1668
+ colorR: aColorR,
1669
+ colorG: aColorG,
1670
+ colorB: aColorB,
1671
+ colorA: aColorA
1672
+ };
1482
1673
  const calculatedCreationTime = now + calculateValue(generalData.particleSystemId, startDelay) * 1e3;
1483
1674
  let wrapper;
1484
1675
  if (normalizedConfig.simulationSpace === "WORLD" /* WORLD */) {
@@ -1518,6 +1709,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1518
1709
  const instanceData = {
1519
1710
  particleSystem,
1520
1711
  wrapper,
1712
+ mappedAttributes,
1521
1713
  elapsedUniform: material.uniforms.elapsed,
1522
1714
  generalData,
1523
1715
  onUpdate,
@@ -1586,7 +1778,8 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1586
1778
  gravity,
1587
1779
  normalizedForceFields,
1588
1780
  onParticleDeath,
1589
- onParticleBirth
1781
+ onParticleBirth,
1782
+ mappedAttributes: ma
1590
1783
  } = props;
1591
1784
  const hasForceFields = normalizedForceFields.length > 0;
1592
1785
  const lifetime = now - creationTime;
@@ -1633,18 +1826,17 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1633
1826
  particleSystem.worldToLocal(gravityVelocity);
1634
1827
  }
1635
1828
  const creationTimes = generalData.creationTimes;
1636
- const attributes = particleSystem.geometry.attributes;
1637
- const isActiveArr = attributes.isActive.array;
1638
- const startLifetimeArr = attributes.startLifetime.array;
1639
- const positionArr = attributes.position.array;
1640
- const lifetimeArr = attributes.lifetime.array;
1829
+ const isActiveArr = ma.isActive.array;
1830
+ const startLifetimeArr = ma.startLifetime.array;
1831
+ const positionArr = ma.position.array;
1832
+ const lifetimeArr = ma.lifetime.array;
1641
1833
  const creationTimesLength = creationTimes.length;
1642
1834
  let positionNeedsUpdate = false;
1643
1835
  let lifetimeNeedsUpdate = false;
1644
1836
  _modifierParams.delta = delta;
1645
1837
  _modifierParams.generalData = generalData;
1646
1838
  _modifierParams.normalizedConfig = normalizedConfig;
1647
- _modifierParams.attributes = attributes;
1839
+ _modifierParams.attributes = ma;
1648
1840
  for (let index = 0; index < creationTimesLength; index++) {
1649
1841
  if (isActiveArr[index]) {
1650
1842
  const particleLifetime = now - creationTimes[index];
@@ -1688,8 +1880,8 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1688
1880
  }
1689
1881
  }
1690
1882
  }
1691
- if (positionNeedsUpdate) attributes.position.needsUpdate = true;
1692
- if (lifetimeNeedsUpdate) attributes.lifetime.needsUpdate = true;
1883
+ if (positionNeedsUpdate) ma.position.needsUpdate = true;
1884
+ if (lifetimeNeedsUpdate) ma.lifetime.needsUpdate = true;
1693
1885
  if (isEnabled && (looping || lifetime < duration * 1e3)) {
1694
1886
  const emissionDelta = now - lastEmissionTime;
1695
1887
  const neededParticlesByTime = emission.rateOverTime ? Math.floor(
@@ -1776,7 +1968,7 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1776
1968
  if (onParticleBirth)
1777
1969
  onParticleBirth(
1778
1970
  particleIndex,
1779
- attributes.position.array,
1971
+ ma.position.array,
1780
1972
  velocities[particleIndex],
1781
1973
  now
1782
1974
  );
@@ -1803,6 +1995,6 @@ var updateParticleSystems = (cycleData) => {
1803
1995
  );
1804
1996
  };
1805
1997
 
1806
- export { CurveFunctionId, EmitFrom, ForceFieldFalloff, ForceFieldType, LifeTimeCurve, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
1998
+ export { CurveFunctionId, EmitFrom, ForceFieldFalloff, ForceFieldType, LifeTimeCurve, RendererType, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
1807
1999
  //# sourceMappingURL=index.js.map
1808
2000
  //# sourceMappingURL=index.js.map