roavatar-renderer 1.5.5 → 1.5.6

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.d.ts CHANGED
@@ -1530,7 +1530,7 @@ export declare function getOriginalAttachmentPosition(attachment: Instance): Vec
1530
1530
 
1531
1531
  export declare function getOriginalSize(part: Instance): Vector3;
1532
1532
 
1533
- export declare function getRandomBetweenInclusive(min: number, max: number): number;
1533
+ export declare function getRandomBetweenInclusive(min: number, max: number, randomVal?: number): number;
1534
1534
 
1535
1535
  export declare function getRigExtentsWorld(rig: Instance): [Vector3, Vector3];
1536
1536
 
@@ -2187,7 +2187,7 @@ export declare type Mat3x3 = [number, number, number, number, number, number, nu
2187
2187
  /** @category Mesh */
2188
2188
  export declare type Mat4x4 = [number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number];
2189
2189
 
2190
- export declare function mathRandom(min: number, max: number): number;
2190
+ export declare function mathRandom(min: number, max: number, randomVal?: number): number;
2191
2191
 
2192
2192
  /** @category Outfit */
2193
2193
  export declare const MaxOneOfAssetTypes: string[];
@@ -2637,6 +2637,23 @@ export declare const ParticleEmitterShapeInOut: {
2637
2637
  InAndOut: number;
2638
2638
  };
2639
2639
 
2640
+ /**@category DataModelEnum */
2641
+ export declare const ParticleFlipbookLayout: {
2642
+ None: number;
2643
+ Grid2x2: number;
2644
+ Grid4x4: number;
2645
+ Grid8x8: number;
2646
+ Custom: number;
2647
+ };
2648
+
2649
+ /**@category DataModelEnum */
2650
+ export declare const ParticleFlipbookMode: {
2651
+ Loop: number;
2652
+ OneShot: number;
2653
+ PingPong: number;
2654
+ Random: number;
2655
+ };
2656
+
2640
2657
  /**@category DataModelEnum */
2641
2658
  export declare const ParticleOrientation: {
2642
2659
  FacingCamera: number;
package/dist/index.js CHANGED
@@ -27478,6 +27478,19 @@ class RBXSimpleView {
27478
27478
  }
27479
27479
  const magic = "<roblox!";
27480
27480
  const xmlMagic = "<roblox ";
27481
+ const ParticleFlipbookLayout = {
27482
+ "None": 0,
27483
+ "Grid2x2": 1,
27484
+ "Grid4x4": 2,
27485
+ "Grid8x8": 3,
27486
+ "Custom": 4
27487
+ };
27488
+ const ParticleFlipbookMode = {
27489
+ "Loop": 0,
27490
+ "OneShot": 1,
27491
+ "PingPong": 2,
27492
+ "Random": 3
27493
+ };
27481
27494
  const PartType = {
27482
27495
  "Ball": 0,
27483
27496
  "Block": 1,
@@ -29886,7 +29899,7 @@ const FLAGS = {
29886
29899
  ENABLE_API_RBX_CACHE: true,
29887
29900
  ROAVATAR_DATA_URL: "rbxassetid://102463700065175",
29888
29901
  //url of model to load that lists issues with specific versions
29889
- ROAVATAR_TRYON_PLACE: 135979364355750,
29902
+ ROAVATAR_TRYON_PLACE: 122920847927474,
29890
29903
  ASSETDELIVERY_V2: true,
29891
29904
  ASSET_REQUEST_PRIORITY: "high",
29892
29905
  API_DOMAIN: "roblox.com",
@@ -32164,11 +32177,11 @@ async function Wait(time2) {
32164
32177
  }, time2 * 1e3);
32165
32178
  });
32166
32179
  }
32167
- function getRandomBetweenInclusive(min, max) {
32168
- return Math.random() * (max + 1 - min) + min;
32180
+ function getRandomBetweenInclusive(min, max, randomVal = Math.random()) {
32181
+ return randomVal * (max + 1 - min) + min;
32169
32182
  }
32170
- function mathRandom(min, max) {
32171
- return Math.floor(getRandomBetweenInclusive(min, max));
32183
+ function mathRandom(min, max, randomVal = Math.random()) {
32184
+ return Math.floor(getRandomBetweenInclusive(min, max, randomVal));
32172
32185
  }
32173
32186
  async function imageUrlToDataUrl(imageUrl) {
32174
32187
  const response = await fetch(imageUrl);
@@ -42574,12 +42587,12 @@ class ModelLayersDesc {
42574
42587
  }
42575
42588
  for (const deformer of this.targetDeformers) {
42576
42589
  if (deformer) {
42577
- meshPromises.push(promiseForMesh(deformer.targetCage));
42590
+ meshPromises.push(promiseForMesh(deformer.targetCage, true));
42578
42591
  }
42579
42592
  }
42580
42593
  for (const enclosedLayer of this.layers) {
42581
- meshPromises.push(promiseForMesh(enclosedLayer.cage));
42582
- meshPromises.push(promiseForMesh(enclosedLayer.reference));
42594
+ meshPromises.push(promiseForMesh(enclosedLayer.cage, true));
42595
+ meshPromises.push(promiseForMesh(enclosedLayer.reference, true));
42583
42596
  if (enclosedLayer.mesh) meshPromises.push(promiseForMesh(enclosedLayer.mesh, true));
42584
42597
  }
42585
42598
  const values = await Promise.all(meshPromises);
@@ -42600,14 +42613,14 @@ class ModelLayersDesc {
42600
42613
  inheritSkeleton(targetCage, targetMesh);
42601
42614
  }
42602
42615
  const distDeformer = this.targetDeformers[0];
42603
- const dist_mesh = distDeformer ? meshMap.get(distDeformer.targetCage).clone() : meshMap.get(this.targetCages[0]);
42616
+ const dist_mesh = distDeformer ? meshMap.get(distDeformer.targetCage).clone() : meshMap.get(this.targetCages[0]).clone();
42604
42617
  const dist_mesh_mesh = meshMap.get(this.targetMeshes[0]);
42605
42618
  offsetMesh(dist_mesh, this.targetOffsets[0]);
42606
42619
  scaleMesh(dist_mesh, this.targetSizes[0].divide(new Vector32().fromVec3(dist_mesh_mesh.size)));
42607
42620
  offsetMesh(dist_mesh, this.targetCFrames[0]);
42608
42621
  for (let i = 1; i < this.targetCages.length; i++) {
42609
42622
  const deformer = this.targetDeformers[i];
42610
- const targetCage = deformer ? meshMap.get(deformer.targetCage).clone() : meshMap.get(this.targetCages[i]);
42623
+ const targetCage = deformer ? meshMap.get(deformer.targetCage).clone() : meshMap.get(this.targetCages[i]).clone();
42611
42624
  const targetMesh = meshMap.get(this.targetMeshes[i]);
42612
42625
  offsetMesh(targetCage, this.targetOffsets[i]);
42613
42626
  scaleMesh(targetCage, this.targetSizes[i].divide(new Vector32().fromVec3(targetMesh.size)));
@@ -42619,8 +42632,8 @@ class ModelLayersDesc {
42619
42632
  targetMeshes.push(dist_mesh.clone());
42620
42633
  const uvToHits = [];
42621
42634
  for (const layer of this.layers) {
42622
- const cage = meshMap.get(layer.cage);
42623
- const reference = meshMap.get(layer.reference);
42635
+ const cage = meshMap.get(layer.cage)?.clone();
42636
+ const reference = meshMap.get(layer.reference)?.clone();
42624
42637
  if (!cage || !reference) {
42625
42638
  throw new Error("this isnt possible, shut up typescript");
42626
42639
  }
@@ -42795,8 +42808,8 @@ class HSRDesc {
42795
42808
  const cacheId = `${layer.mesh}-${layer.reference}-${layer.cage}`;
42796
42809
  const cacheEntry = FLAGS.CACHE_HSR_HITS ? CACHE_uvToHits.get(cacheId) : void 0;
42797
42810
  if (!cacheEntry) {
42798
- meshPromises.push(promiseForMesh(enclosedLayer.cage));
42799
- meshPromises.push(promiseForMesh(enclosedLayer.reference));
42811
+ meshPromises.push(promiseForMesh(enclosedLayer.cage, true));
42812
+ meshPromises.push(promiseForMesh(enclosedLayer.reference, true));
42800
42813
  if (enclosedLayer.mesh) meshPromises.push(promiseForMesh(enclosedLayer.mesh, true));
42801
42814
  }
42802
42815
  }
@@ -42816,8 +42829,8 @@ class HSRDesc {
42816
42829
  const cacheEntry = FLAGS.CACHE_HSR_HITS ? CACHE_uvToHits.get(cacheId) : void 0;
42817
42830
  const latestUvToHitsMap = cacheEntry ? cacheEntry : /* @__PURE__ */ new Map();
42818
42831
  if (!cacheEntry && !isTransparent) {
42819
- const cage = meshMap.get(layer.cage);
42820
- const reference = meshMap.get(layer.reference);
42832
+ const cage = meshMap.get(layer.cage)?.clone();
42833
+ const reference = meshMap.get(layer.reference)?.clone();
42821
42834
  const mesh = layer.mesh ? meshMap.get(layer.mesh) : void 0;
42822
42835
  if (!cage || !reference) {
42823
42836
  throw new Error("this isnt possible, shut up typescript");
@@ -49370,13 +49383,16 @@ const __vite_glob_0_0 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
49370
49383
  }, Symbol.toStringTag, { value: "Module" }));
49371
49384
  const particle_vertexShader = `
49372
49385
  attribute vec3 instanceColor;
49373
- attribute vec2 instanceSeedTime;
49386
+ attribute vec3 instanceSeedTime;
49374
49387
  attribute float instanceOpacity;
49388
+ attribute vec4 instanceFlipbook;
49375
49389
 
49376
49390
  varying vec2 vUv;
49377
49391
  varying vec3 vInstanceColor;
49378
49392
  varying float vInstanceOpacity;
49379
- varying vec2 vInstanceSeedTime;
49393
+ varying vec3 vInstanceSeedTime;
49394
+ varying vec2 vFlipbookUv0;
49395
+ varying vec2 vFlipbookUv1;
49380
49396
 
49381
49397
  uniform float uZOffset;
49382
49398
 
@@ -49385,6 +49401,8 @@ void main() {
49385
49401
  vInstanceColor = instanceColor;
49386
49402
  vInstanceOpacity = instanceOpacity;
49387
49403
  vInstanceSeedTime = instanceSeedTime;
49404
+ vFlipbookUv0 = instanceFlipbook.xy;
49405
+ vFlipbookUv1 = instanceFlipbook.zw;
49388
49406
 
49389
49407
  vec4 modelViewPosition = modelViewMatrix * instanceMatrix * vec4(position, 1.0);
49390
49408
 
@@ -49398,19 +49416,28 @@ const particle_fragmentShader = `
49398
49416
  varying vec2 vUv;
49399
49417
  varying vec3 vInstanceColor;
49400
49418
  varying float vInstanceOpacity;
49401
- varying vec2 vInstanceSeedTime;
49419
+ varying vec3 vInstanceSeedTime;
49420
+ varying vec2 vFlipbookUv0;
49421
+ varying vec2 vFlipbookUv1;
49402
49422
 
49403
49423
  uniform sampler2D uColorMap;
49404
49424
  uniform sampler2D uAlphaMap;
49405
49425
  uniform sampler2D uMap;
49406
49426
  uniform float uOpacity;
49427
+ uniform vec2 uFlipbookSize;
49407
49428
 
49408
49429
  void main() {
49409
49430
  float seed = vInstanceSeedTime.x;
49410
49431
  float time = vInstanceSeedTime.y;
49432
+ float flipbookFrameTime = vInstanceSeedTime.z;
49433
+
49434
+ // Sample the texture using the UV coordinates (for both frames)
49435
+ vec4 texColor0 = texture2D(uMap, vUv * uFlipbookSize + vFlipbookUv0);
49436
+ vec4 texColor1 = texture2D(uMap, vUv * uFlipbookSize + vFlipbookUv1);
49437
+
49438
+ float frameTransition = mod(time, flipbookFrameTime) / flipbookFrameTime;
49439
+ vec4 texColor = texColor0 * (1.0 - frameTransition) + texColor1 * frameTransition;
49411
49440
 
49412
- // Sample the texture using the UV coordinates
49413
- vec4 texColor = texture2D(uMap, vUv);
49414
49441
  vec4 alphaTex = texture2D(uAlphaMap, vec2(time, seed));
49415
49442
  vec4 colorTex = texture2D(uColorMap, vec2(time, seed));
49416
49443
 
@@ -49420,6 +49447,8 @@ void main() {
49420
49447
  // Apply opacity to the texture alpha
49421
49448
  vec4 opacityColor = tintedColor * vec4(1.0, 1.0, 1.0, uOpacity * vInstanceOpacity) * alphaTex.r;
49422
49449
 
49450
+ //#ADDITIVE_INSERT
49451
+
49423
49452
  // Apply that weird color things sparkles have
49424
49453
  vec4 finalColor = opacityColor;
49425
49454
  finalColor.rgb = mix(opacityColor.rgb, opacityColor.rgb * colorTex.rgb, colorTex.a);
@@ -49427,6 +49456,12 @@ void main() {
49427
49456
  gl_FragColor = finalColor;
49428
49457
  }
49429
49458
  `;
49459
+ const particle_fragmentShader_additive = particle_fragmentShader.replace(
49460
+ "//#ADDITIVE_INSERT",
49461
+ `if (opacityColor.r + opacityColor.g + opacityColor.b <= 0.05) {
49462
+ discard;
49463
+ }`
49464
+ );
49430
49465
  function randomBetween(min, max) {
49431
49466
  return Math.random() * (max - min) + min;
49432
49467
  }
@@ -49455,17 +49490,22 @@ class Particle {
49455
49490
  this.velocity = velocity;
49456
49491
  this.rotationSpeed = rotationSpeed;
49457
49492
  }
49493
+ get intSeed() {
49494
+ return Math.floor(this.seed * 1e6);
49495
+ }
49458
49496
  camDistance(renderScene) {
49459
49497
  const cameraPos = new Vector32(...renderScene.camera.position.toArray());
49460
49498
  const particlePos = this.position;
49461
49499
  const distance2 = cameraPos.minus(particlePos).magnitude();
49462
49500
  return distance2;
49463
49501
  }
49464
- getMatrix(renderScene, size, orientation) {
49502
+ getMatrix(renderScene, size, orientation, squash) {
49465
49503
  const camera = renderScene.camera;
49466
49504
  const particlePos = new Vector3$1(...this.position.toVec3());
49467
49505
  const translation = new Matrix4().makeTranslation(particlePos);
49468
- const scale = new Matrix4().makeScale(size, size, 1);
49506
+ const sizeX = squash > 0 ? size / (1 + squash) : size * (1 - squash);
49507
+ const sizeY = squash > 0 ? size * (1 + squash) : size / (1 - squash);
49508
+ const scale = new Matrix4().makeScale(sizeX, sizeY, 1);
49469
49509
  switch (orientation) {
49470
49510
  case ParticleOrientation.FacingCameraWorldUp: {
49471
49511
  const cameraLookVector = new Vector3$1();
@@ -49495,13 +49535,29 @@ class Particle {
49495
49535
  return final;
49496
49536
  }
49497
49537
  case ParticleOrientation.VelocityParallel: {
49498
- const normalizedVelocity = new Vector3$1(...this.velocity.normalize().toVec3());
49499
- const rotationParticlePosMatrix = new Matrix4().lookAt(particlePos, camera.position, normalizedVelocity);
49500
- const _pos = new Vector3$1();
49501
- const _scale = new Vector3$1();
49502
- const rotationQuat = new Quaternion();
49503
- rotationParticlePosMatrix.decompose(_pos, rotationQuat, _scale);
49504
- const rotation = new Matrix4().makeRotationFromQuaternion(rotationQuat);
49538
+ const toCamera = new Vector3$1(0, 0, -1).applyQuaternion(camera.quaternion);
49539
+ const velocityVector = new Vector3$1(...this.velocity.toVec3());
49540
+ const vY = velocityVector.normalize();
49541
+ const vX = new Vector3$1().crossVectors(toCamera.normalize(), vY).normalize();
49542
+ const vZ = new Vector3$1().crossVectors(vX, vY).normalize();
49543
+ const rotation = new Matrix4().set(
49544
+ vX.x,
49545
+ vY.x,
49546
+ vZ.x,
49547
+ 0,
49548
+ vX.y,
49549
+ vY.y,
49550
+ vZ.y,
49551
+ 0,
49552
+ vX.z,
49553
+ vY.z,
49554
+ vZ.z,
49555
+ 0,
49556
+ 0,
49557
+ 0,
49558
+ 0,
49559
+ 1
49560
+ );
49505
49561
  const flatRotation = new Matrix4().makeRotationAxis(new Vector3$1(0, 0, 1), rad(this.rotation + 90));
49506
49562
  const final = translation.multiply(rotation).multiply(flatRotation).multiply(scale);
49507
49563
  return final;
@@ -49515,6 +49571,30 @@ class Particle {
49515
49571
  }
49516
49572
  }
49517
49573
  }
49574
+ getFlipbookIndex(total, isNext, framerate, mode, startRandom) {
49575
+ const rng = new RNG(this.intSeed + 324);
49576
+ const randomVal = rng.nextFloat();
49577
+ let offset = startRandom ? mathRandom(0, total - 1, randomVal) : 0;
49578
+ switch (mode) {
49579
+ case ParticleFlipbookMode.Loop:
49580
+ offset += Math.floor(this.time * framerate);
49581
+ break;
49582
+ case ParticleFlipbookMode.OneShot:
49583
+ offset += Math.round(this.time * total);
49584
+ break;
49585
+ case ParticleFlipbookMode.PingPong:
49586
+ offset += Math.floor(this.time * framerate);
49587
+ break;
49588
+ case ParticleFlipbookMode.Random:
49589
+ offset += mathRandom(0, total - 1, new RNG(this.intSeed + 334 + Math.floor(this.time * framerate)).nextFloat());
49590
+ break;
49591
+ }
49592
+ if (isNext) offset += 1;
49593
+ if (offset >= total) {
49594
+ offset %= total;
49595
+ }
49596
+ return offset;
49597
+ }
49518
49598
  tick(dt, drag, acceleration) {
49519
49599
  this.time += specialClamp(dt, 0, this.lifetime);
49520
49600
  this.position = this.position.add(this.velocity.multiply(new Vector32(dt, dt, dt)));
@@ -49547,8 +49627,16 @@ class EmitterDesc extends DisposableDesc {
49547
49627
  blending = AdditiveBlending;
49548
49628
  color = new ColorSequence();
49549
49629
  size = new NumberSequence();
49630
+ squash = new NumberSequence([new NumberSequenceKeypoint(0, 0, 0)]);
49550
49631
  transparency = new NumberSequence([new NumberSequenceKeypoint(0, 0, 0)]);
49551
49632
  normalizeSizeKeypointTime = true;
49633
+ flipbookLayout = ParticleFlipbookLayout.None;
49634
+ flipbookBlendFrames = true;
49635
+ flipbookFramerate = new NumberRange(1, 1);
49636
+ flipbookMode = ParticleFlipbookMode.Loop;
49637
+ flipbookSizeX = 1;
49638
+ flipbookSizeY = 1;
49639
+ flipbookStartRandom = false;
49552
49640
  //requires recompilation
49553
49641
  rate = 10;
49554
49642
  colorTexture;
@@ -49558,7 +49646,9 @@ class EmitterDesc extends DisposableDesc {
49558
49646
  instanceOpacityBuffer;
49559
49647
  instanceColorBuffer;
49560
49648
  instanceSeedTimeBuffer;
49649
+ instanceFlipbookBuffer;
49561
49650
  result;
49651
+ resultMaterial;
49562
49652
  particles = [];
49563
49653
  initialParticleCount = 0;
49564
49654
  get maxCount() {
@@ -49570,7 +49660,7 @@ class EmitterDesc extends DisposableDesc {
49570
49660
  return this.texture === other.texture && this.alphaTexture === other.alphaTexture && this.colorTexture === other.colorTexture && this.rate === other.rate;
49571
49661
  }
49572
49662
  isSame(other) {
49573
- return !this.needsRegeneration(other) && this.lockedToPart === other.lockedToPart && this.lifetime.isSame(other.lifetime) && this.spreadAngle.isSame(other.spreadAngle) && this.speed.isSame(other.speed) && this.rotation.isSame(other.rotation) && this.rotationSpeed.isSame(other.rotationSpeed) && this.localAcceleration.isSame(other.localAcceleration) && this.acceleration.isSame(other.acceleration) && this.drag === other.drag && this.timeScale === other.timeScale && this.orientation === other.orientation && this.zOffset === other.zOffset && this.offset.isSame(other.offset) && this.shapeInOut === other.shapeInOut && this.opacity === other.opacity && this.lightEmission === other.lightEmission && this.blending === other.blending && this.color.isSame(other.color) && this.size.isSame(other.size) && this.transparency.isSame(other.transparency) && this.normalizeSizeKeypointTime === other.normalizeSizeKeypointTime;
49663
+ return !this.needsRegeneration(other) && this.lockedToPart === other.lockedToPart && this.lifetime.isSame(other.lifetime) && this.spreadAngle.isSame(other.spreadAngle) && this.speed.isSame(other.speed) && this.rotation.isSame(other.rotation) && this.rotationSpeed.isSame(other.rotationSpeed) && this.localAcceleration.isSame(other.localAcceleration) && this.acceleration.isSame(other.acceleration) && this.drag === other.drag && this.timeScale === other.timeScale && this.orientation === other.orientation && this.zOffset === other.zOffset && this.offset.isSame(other.offset) && this.shapeInOut === other.shapeInOut && this.opacity === other.opacity && this.lightEmission === other.lightEmission && this.blending === other.blending && this.color.isSame(other.color) && this.size.isSame(other.size) && this.squash.isSame(other.squash) && this.transparency.isSame(other.transparency) && this.normalizeSizeKeypointTime === other.normalizeSizeKeypointTime && this.flipbookLayout === other.flipbookLayout && this.flipbookBlendFrames === other.flipbookBlendFrames && this.flipbookFramerate.isSame(other.flipbookFramerate) && this.flipbookMode === other.flipbookMode && this.flipbookSizeX === other.flipbookSizeX && this.flipbookSizeY === other.flipbookSizeY && this.flipbookStartRandom === other.flipbookStartRandom;
49574
49664
  }
49575
49665
  fromEmitterDesc(other) {
49576
49666
  this.lockedToPart = other.lockedToPart;
@@ -49593,8 +49683,16 @@ class EmitterDesc extends DisposableDesc {
49593
49683
  this.blending = other.blending;
49594
49684
  this.color = other.color.clone();
49595
49685
  this.size = other.size.clone();
49686
+ this.squash = other.squash.clone();
49596
49687
  this.transparency = other.transparency.clone();
49597
49688
  this.normalizeSizeKeypointTime = other.normalizeSizeKeypointTime;
49689
+ this.flipbookLayout = other.flipbookLayout;
49690
+ this.flipbookBlendFrames = other.flipbookBlendFrames;
49691
+ this.flipbookFramerate = other.flipbookFramerate.clone();
49692
+ this.flipbookMode = other.flipbookMode;
49693
+ this.flipbookSizeX = other.flipbookSizeX;
49694
+ this.flipbookSizeY = other.flipbookSizeY;
49695
+ this.flipbookStartRandom = other.flipbookStartRandom;
49598
49696
  }
49599
49697
  dispose(renderer, scene) {
49600
49698
  const mesh = this.result;
@@ -49618,6 +49716,31 @@ class EmitterDesc extends DisposableDesc {
49618
49716
  }
49619
49717
  return void 0;
49620
49718
  }
49719
+ getFlipbookSize() {
49720
+ let flipbookSizeX = this.flipbookSizeX;
49721
+ let flipbookSizeY = this.flipbookSizeY;
49722
+ switch (this.flipbookLayout) {
49723
+ case ParticleFlipbookLayout.None:
49724
+ flipbookSizeX = 1;
49725
+ flipbookSizeY = 1;
49726
+ break;
49727
+ case ParticleFlipbookLayout.Grid2x2:
49728
+ flipbookSizeX = 2;
49729
+ flipbookSizeY = 2;
49730
+ break;
49731
+ case ParticleFlipbookLayout.Grid4x4:
49732
+ flipbookSizeX = 4;
49733
+ flipbookSizeY = 4;
49734
+ break;
49735
+ case ParticleFlipbookLayout.Grid8x8:
49736
+ flipbookSizeX = 8;
49737
+ flipbookSizeY = 8;
49738
+ break;
49739
+ case ParticleFlipbookLayout.Custom:
49740
+ break;
49741
+ }
49742
+ return [flipbookSizeX, flipbookSizeY];
49743
+ }
49621
49744
  async compileResult(renderer, scene) {
49622
49745
  const originalResult = this.result;
49623
49746
  const texturePromises = [
@@ -49643,8 +49766,11 @@ class EmitterDesc extends DisposableDesc {
49643
49766
  geometry.setAttribute("instanceColor", this.instanceColorBuffer);
49644
49767
  this.instanceOpacityBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount), 1);
49645
49768
  geometry.setAttribute("instanceOpacity", this.instanceOpacityBuffer);
49646
- this.instanceSeedTimeBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount), 2);
49769
+ this.instanceSeedTimeBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount * 3), 3);
49647
49770
  geometry.setAttribute("instanceSeedTime", this.instanceSeedTimeBuffer);
49771
+ this.instanceFlipbookBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount * 4), 4);
49772
+ geometry.setAttribute("instanceFlipbook", this.instanceFlipbookBuffer);
49773
+ const [flipbookSizeX, flipbookSizeY] = this.getFlipbookSize();
49648
49774
  const material = new ShaderMaterial({
49649
49775
  transparent: true,
49650
49776
  depthWrite: false,
@@ -49652,15 +49778,17 @@ class EmitterDesc extends DisposableDesc {
49652
49778
  blending: this.blending,
49653
49779
  opacity: this.opacity,
49654
49780
  vertexShader: particle_vertexShader,
49655
- fragmentShader: particle_fragmentShader,
49781
+ fragmentShader: this.blending === AdditiveBlending ? particle_fragmentShader_additive : particle_fragmentShader,
49656
49782
  uniforms: {
49657
49783
  uMap: { value: mapToUse },
49658
49784
  uAlphaMap: { value: alphaMapToUse },
49659
49785
  uColorMap: { value: colorMapToUse },
49660
49786
  uOpacity: { value: this.opacity },
49661
- uZOffset: { value: this.zOffset }
49787
+ uZOffset: { value: this.zOffset },
49788
+ uFlipbookSize: { value: new Vector2$1(1 / flipbookSizeX, 1 / flipbookSizeY) }
49662
49789
  }
49663
49790
  });
49791
+ this.resultMaterial = material;
49664
49792
  this.result = new InstancedMesh(geometry, material, this.maxCount);
49665
49793
  this.result.name = "Particles";
49666
49794
  this.result.frustumCulled = false;
@@ -49744,24 +49872,47 @@ class EmitterDesc extends DisposableDesc {
49744
49872
  }
49745
49873
  }
49746
49874
  updateResult(renderScene) {
49747
- if (!this.result || !this.instanceColorBuffer || !this.instanceOpacityBuffer || !this.instanceSeedTimeBuffer) return;
49875
+ if (!this.result || !this.instanceColorBuffer || !this.instanceOpacityBuffer || !this.instanceSeedTimeBuffer || !this.instanceFlipbookBuffer) return;
49748
49876
  this.result.count = this.particles.length;
49877
+ const [flipbookSizeX, flipbookSizeY] = this.getFlipbookSize();
49878
+ const flipbookTotal = flipbookSizeX * flipbookSizeY;
49879
+ if (this.resultMaterial) {
49880
+ this.resultMaterial.uniforms.uOpacity.value = this.opacity;
49881
+ this.resultMaterial.uniforms.uZOffset.value = this.zOffset;
49882
+ this.resultMaterial.uniforms.uFlipbookSize.value.set(1 / flipbookSizeX, 1 / flipbookSizeY);
49883
+ }
49749
49884
  for (let i = 0; i < this.result.count; i++) {
49750
49885
  const particle = this.particles[i];
49751
49886
  const time2 = particle.time;
49752
49887
  const normalizedTime = particle.time / particle.lifetime;
49753
49888
  const color = this.color.getValue(normalizedTime);
49754
49889
  const size = this.size.getValue(this.normalizeSizeKeypointTime ? normalizedTime : time2, particle.seed + 0);
49890
+ const squash = this.squash.getValue(this.normalizeSizeKeypointTime ? normalizedTime : time2, particle.seed + 2);
49755
49891
  const opacity = 1 - this.transparency.getValue(normalizedTime, particle.seed + 1);
49756
- this.result.setMatrixAt(i, particle.getMatrix(renderScene, size, this.orientation));
49892
+ const flipbookFramerate = mathRandom(this.flipbookFramerate.Min, this.flipbookFramerate.Max, new RNG(particle.seed + 67).nextFloat());
49893
+ let flipbookFrameTime = this.flipbookMode === ParticleFlipbookMode.OneShot ? particle.lifetime / flipbookTotal : 1 / flipbookFramerate;
49894
+ if (!this.flipbookBlendFrames) flipbookFrameTime = 1e6;
49895
+ this.result.setMatrixAt(i, particle.getMatrix(renderScene, size, this.orientation, squash));
49757
49896
  this.instanceColorBuffer.setXYZ(i, color.R, color.G, color.B);
49758
49897
  this.instanceOpacityBuffer.setX(i, opacity);
49759
- this.instanceSeedTimeBuffer.setXY(i, particle.seed, normalizedTime);
49898
+ this.instanceSeedTimeBuffer.setXYZ(i, particle.seed, normalizedTime, flipbookFrameTime);
49899
+ const flipbookFrame0 = particle.getFlipbookIndex(flipbookTotal, false, flipbookFramerate, this.flipbookMode, this.flipbookStartRandom);
49900
+ const flipbookFrame1 = this.flipbookBlendFrames ? particle.getFlipbookIndex(flipbookTotal, true, flipbookFramerate, this.flipbookMode, this.flipbookStartRandom) : flipbookFrame0;
49901
+ const column0 = flipbookFrame0 % flipbookSizeX;
49902
+ const row0 = Math.floor(flipbookFrame0 / flipbookSizeX);
49903
+ const column1 = flipbookFrame1 % flipbookSizeX;
49904
+ const row1 = Math.floor(flipbookFrame1 / flipbookSizeX);
49905
+ const u0 = column0 * 1 / flipbookSizeX;
49906
+ const v0 = (flipbookSizeY - 1 - row0) * 1 / flipbookSizeY;
49907
+ const u1 = column1 * 1 / flipbookSizeX;
49908
+ const v1 = (flipbookSizeY - 1 - row1) * 1 / flipbookSizeY;
49909
+ this.instanceFlipbookBuffer.setXYZW(i, u0, v0, u1, v1);
49760
49910
  }
49761
49911
  this.result.instanceMatrix.needsUpdate = true;
49762
49912
  this.instanceColorBuffer.needsUpdate = true;
49763
49913
  this.instanceOpacityBuffer.needsUpdate = true;
49764
49914
  this.instanceSeedTimeBuffer.needsUpdate = true;
49915
+ this.instanceFlipbookBuffer.needsUpdate = true;
49765
49916
  }
49766
49917
  }
49767
49918
  class EmitterGroupDesc extends RenderDesc {
@@ -49904,6 +50055,7 @@ class EmitterGroupDesc extends RenderDesc {
49904
50055
  if (child.HasProperty("Drag")) emitterDesc.drag = child.Prop("Drag");
49905
50056
  if (child.HasProperty("TimeScale")) emitterDesc.timeScale = child.Prop("TimeScale");
49906
50057
  if (child.HasProperty("Size")) emitterDesc.size = child.Prop("Size");
50058
+ if (child.HasProperty("Squash")) emitterDesc.squash = child.Prop("Squash");
49907
50059
  if (child.HasProperty("Color")) emitterDesc.color = child.Prop("Color");
49908
50060
  if (child.HasProperty("Texture")) emitterDesc.texture = child.Prop("Texture");
49909
50061
  if (child.HasProperty("Transparency")) emitterDesc.transparency = child.Prop("Transparency");
@@ -49912,6 +50064,13 @@ class EmitterGroupDesc extends RenderDesc {
49912
50064
  if (child.HasProperty("ZOffset")) emitterDesc.zOffset = child.Prop("ZOffset");
49913
50065
  if (child.HasProperty("Orientation")) emitterDesc.orientation = child.Prop("Orientation");
49914
50066
  if (child.HasProperty("LockedToPart")) emitterDesc.lockedToPart = child.Prop("LockedToPart");
50067
+ emitterDesc.flipbookLayout = child.PropOrDefault("FlipbookLayout", emitterDesc.flipbookLayout);
50068
+ emitterDesc.flipbookBlendFrames = child.PropOrDefault("FlipbookBlendFrames", emitterDesc.flipbookBlendFrames);
50069
+ emitterDesc.flipbookFramerate = child.PropOrDefault("FlipbookFramerate", emitterDesc.flipbookFramerate);
50070
+ emitterDesc.flipbookMode = child.PropOrDefault("FlipbookMode", emitterDesc.flipbookMode);
50071
+ emitterDesc.flipbookSizeX = child.PropOrDefault("FlipbookSizeX", emitterDesc.flipbookSizeX);
50072
+ emitterDesc.flipbookSizeY = child.PropOrDefault("FlipbookSizeY", emitterDesc.flipbookSizeY);
50073
+ emitterDesc.flipbookStartRandom = child.PropOrDefault("FlipbookStartRandom", emitterDesc.flipbookStartRandom);
49915
50074
  this.emitterDescs.push(emitterDesc);
49916
50075
  }
49917
50076
  fromSparkles(child) {
@@ -50527,8 +50686,8 @@ class RBXRenderer {
50527
50686
  }
50528
50687
  /**Sets up the THREE.js renderer */
50529
50688
  static create(canvas) {
50530
- RBXRenderer.renderer = new WebGLRenderer({ antialias: true, alpha: true, canvas });
50531
- RBXRenderer.renderer.setClearColor(new Color(1, 0, 1), 0);
50689
+ RBXRenderer.renderer = new WebGLRenderer({ antialias: true, alpha: true, premultipliedAlpha: false, canvas });
50690
+ if (RBXRenderer.renderer) RBXRenderer.renderer.setClearColor(new Color(0, 0, 0), 0);
50532
50691
  RBXRenderer.renderer.outputColorSpace = SRGBColorSpace;
50533
50692
  RBXRenderer.renderer.shadowMap.enabled = true;
50534
50693
  RBXRenderer.renderer.shadowMap.type = PCFSoftShadowMap;
@@ -50698,6 +50857,7 @@ class RBXRenderer {
50698
50857
  */
50699
50858
  static setBackgroundTransparent(transparent) {
50700
50859
  RBXRenderer.backgroundTransparent = transparent;
50860
+ if (RBXRenderer.renderer) RBXRenderer.renderer.setClearColor(new Color(0, 0, 0), 0);
50701
50861
  for (const renderScene of RBXRenderer.scenes) {
50702
50862
  if (RBXRenderer.backgroundTransparent) {
50703
50863
  renderScene.scene.background = null;
@@ -51687,6 +51847,8 @@ export {
51687
51847
  OutfitRenderer,
51688
51848
  PartType,
51689
51849
  ParticleEmitterShapeInOut,
51850
+ ParticleFlipbookLayout,
51851
+ ParticleFlipbookMode,
51690
51852
  ParticleOrientation,
51691
51853
  Property,
51692
51854
  PropertyTypeInfo,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roavatar-renderer",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "description": "A renderer for Roblox avatars, used by the RoAvatar extension.",
5
5
  "author": "steinan",
6
6
  "type": "module",