dedup: animation samplers
Is your feature request related to a problem? Please describe. Currently dedup is only available for accessors, meshes, images, materials, and skins, but in gltf spec, 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
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<string, AnimationSampler[]>();
const duplicates = new Map<AnimationSampler, AnimationSampler>();
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.`);
}
Another thing to discuss is in dedupAnimationSamplers, input and output are compared by reference, but hashAnimationSampler uses value hash, would it be better to have something like a Map-based reference counter, or is there some unique object id elsewhere