Skip to content

Commit

Permalink
set frame id
Browse files Browse the repository at this point in the history
  • Loading branch information
jerzakm committed Feb 14, 2024
1 parent a8667ea commit 2a58cde
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/young-beans-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@threejs-kit/instanced-sprite-mesh": minor
---

Allow setting a given frameID per instance with .frame.setAt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ type PLAY_MODE = "FORWARD" | "REVERSE" | "PAUSE" | "PINGPONG"
- **setAt: (instanceId: number, offset: number)**
- **randomizeAll: (scalar: number = 1)** - offset all sprites by a random value (0-1) multiplied by scalar

### `.frame`
- **setAt: (instanceId: number, frameId: number, animation?: string)** - Set the instance at a specific frame. FrameID is an n-th frame in the animation if the name is provided, otherwise if not set, it's an n-th frameId of the entire spritesheet.

### `.loop`
methods to control whether sprite animation should be looped
- **.loop.setAt( instanceId: number, enable: boolean )** - sets per instance loop mode
Expand All @@ -84,7 +87,6 @@ type PLAY_MODE = "FORWARD" | "REVERSE" | "PAUSE" | "PINGPONG"
- **.fps(value: number)** - set fps playback rate for the spritesheet



### `.play`
Utility function that combines `.animation`, `.loop` and `.playmode`
```ts
Expand Down
17 changes: 14 additions & 3 deletions packages/instanced-sprite-mesh/src/InstancedSpriteMesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export const PLAY_MODES = {
} as const;

type PLAY_MODE = keyof typeof PLAY_MODES;
type PLAY_MODE_Vals = (typeof PLAY_MODES)[PLAY_MODE];

export class InstancedSpriteMesh<
T extends Material,
Expand All @@ -40,7 +39,6 @@ export class InstancedSpriteMesh<
private _spriteMaterial: ShaderMaterial;
private _spritesheet?: SpritesheetFormat | undefined;
private _animationMap: Map<V, number>;
private _time: number = 0;
private _fps: number = 15;
private _timer: Timer;

Expand Down Expand Up @@ -118,7 +116,6 @@ export class InstancedSpriteMesh<
this.compute.animationRunner.material.uniforms["spritesheetData"].value =
dataTexture;
// @ts-ignore
// todo type this with named animations?
this._animationMap = animMap;
}

Expand Down Expand Up @@ -146,6 +143,20 @@ export class InstancedSpriteMesh<
};
}

get frame() {
return {
setAt: (instanceId: number, frameId: number, animation?: V) => {
let id = frameId;
if (animation) {
const frameMeta = this.spritesheet?.animations[animation][frameId][0];
id = frameMeta;
}

this.compute.utils.updateFrameAt(instanceId, id);
},
};
}

get playmode() {
return {
setAt: (instanceId: number, playmode: PLAY_MODE) => {
Expand Down
29 changes: 27 additions & 2 deletions packages/instanced-sprite-mesh/src/animationRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ const animProgressCompute = /*glsl*/ `
float animLength = readData(animationId, 1.f, spritesheetData).r;
float totalTime = animLength / fps;
// new delta is % of animation
float newProgress = deltaTime / totalTime;
// add new delta to saved progress
Expand Down Expand Up @@ -102,6 +101,10 @@ const animProgressCompute = /*glsl*/ `
float frameId = floor(animLength * frameTimedId);
float spritesheetFrameId = readData(frameId, 2.f + animationId, spritesheetData).r;
if(instructions.a >=10.){
spritesheetFrameId = instructions.a - 10.;
}
// Picked sprite frame that goes to material
progressValue.r = spritesheetFrameId;
Expand Down Expand Up @@ -200,9 +203,10 @@ export const initAnimationRunner = (
// R - animationId
// G - offset
// B - 0 - forward 1 - reverse 2 - pause 3 - pingpong | loop if over 10
// A? - -1 - restart, 0 - nothing, manually picked ID of a frame
// A? - -1 - restart, 0 - nothing, 10> manually picked ID of a frame (id - 10)

let needsUpdate = false;
let needsClearFrameSet = false;

const updateAnimationAt = (instanceId: number, animationId: number) => {
const index = instanceId * 4;
Expand All @@ -222,12 +226,32 @@ export const initAnimationRunner = (
needsUpdate = true;
};

const updateFrameAt = (instanceId: number, frameId: number) => {
const index = instanceId * 4;
progressDataTexture.image.data[index + 3] = frameId + 10;
needsUpdate = true;
needsClearFrameSet = true;
};

const clearFrameSet = () => {
for (let i = 0; i < instanceCount; i++) {
const index = i * 4;
progressDataTexture.image.data[index + 3] = 0;
}
needsUpdate = true;
};

const update = () => {
if (needsUpdate) {
progressDataTexture.needsUpdate = true;
needsUpdate = false;
}
gpuCompute.compute();

if (needsClearFrameSet) {
clearFrameSet();
needsClearFrameSet = false;
}
};

// todo make this nicer after deciding on api
Expand All @@ -239,6 +263,7 @@ export const initAnimationRunner = (
updateAnimationAt,
updateOffsetAt,
updatePlaymodeAt,
updateFrameAt,
},
update,
};
Expand Down

0 comments on commit 2a58cde

Please sign in to comment.