donmccurdy / donmccurdy/glTF-Transform
dedup: animation samplers
- Dominant language
- TypeScript
- Stars
- 2k
- Forks
- 206
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 16
Description
**Is your feature request related to a problem? Please describe.**
Currently [dedup](https://github.com/donmccurdy/glTF-Transform/blob/main/packages/functions/src/dedup.ts) is only available for accessors, meshes, images, materials, and skins, but in gltf [spec](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#animations), samplers are defined to be able to be reused, this should help in case of models with duplicates in samplers.
**Describe the solution you'd like**
Add a `PropertyType.ANIMATION_SAMPLER` to `options.propertyTypes` of `dedup`, that enables animation sampler deduplication inside every gltf animation.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
Attach some code here
```typescript
function hashAnimationSampler(sampler: AnimationSampler): string {
const hashKeys: (string | number | boolean)[] = [sampler.getInterpolation()];
const input = sampler.getInput();
if (input) {
hashKeys.push(
input.getCount(),
input.getType(),
input.getComponentType(),
input.getNormalized(),
input.getSparse(),
);
}
const output = sampler.getOutput();
if (output) {
hashKeys.push(
output.getCount(),
output.getType(),
output.getComponentType(),
output.getNormalized(),
output.getSparse(),
);
}
return hashKeys.join(':');
}
function dedupAnimationSamplers(document: Document): void {
const logger = document.getLogger();
const root = document.getRoot();
const animations = root.listAnimations();
const samplerMap = new Map();
const duplicates = new Map();
let duplicateCount = 0, totalCount = 0;
for (let i = 0, length = animations.length; i < length; i++) {
const animation = animations[i];
const samplers = animation.listSamplers();
totalCount += samplers.length;
for (let j = 0, samplersLength = samplers.length; j < samplersLength; j++) {
const sampler = samplers[j];
if (duplicates.has(sampler)) continue;
const hashKey = hashAnimationSampler(sampler);
const values = samplerMap.get(hashKey);
if (!values) {
samplerMap.set(hashKey, [sampler]);
continue;
}
let isDuplicate = false;
for (let k = 0, valueCount = values.length; k < valueCount; k++) {
const value = values[k];
// Instead of equals(), only do shallow compare here
// For a deep compare, dedup accessors before this
if (sampler.getInterpolation() === value.getInterpolation() &&
sampler.getInput() === value.getInput() &&
sampler.getOutput() === value.getOutput()) {
duplicates.set(sampler, value);
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
values.push(sampler);
}
}
duplicateCount += duplicates.size;
duplicates.forEach((dst, src) => {
src.listParents().forEach((property) => {
if (!(property instanceof Root)) property.swap(src, dst);
});
src.dispose();
});
samplerMap.clear();
duplicates.clear();
}
logger.debug(`${NAME}: Merged ${duplicateCount} of ${totalCount} animation samplers.`);
}
```
Contributor guide
Research direction
Start in packages/functions/src/dedup.ts and trace how options.propertyTypes selects the resource types handled by dedup. Confirm how animation samplers are represented and referenced, then implement the requested option so duplicate samplers are merged within each glTF animation while preserving existing deduplication behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100