/
dequantize.ts
65 lines (55 loc) · 2.27 KB
/
dequantize.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import type { Accessor, Document, Primitive, Transform } from '@gltf-transform/core';
import { MeshQuantization } from '@gltf-transform/extensions';
import { createTransform } from './utils';
const NAME = 'dequantize';
/** Options for the {@link dequantize} function. */
export interface DequantizeOptions {
/**
* Pattern (regex) used to filter vertex attribute semantics for quantization.
* Default: `/^((?!JOINTS_).)*$/`.
*/
pattern?: RegExp;
}
const DEQUANTIZE_DEFAULTS: DequantizeOptions = {
pattern: /^((?!JOINTS_).)*$/,
};
/**
* Dequantize {@link Primitive Primitives}, removing {@link MeshQuantization `KHR_mesh_quantization`}
* if present. Dequantization will increase the size of the mesh on disk and in memory, but may be
* necessary for compatibility with applications that don't support quantization.
*/
export function dequantize(_options: DequantizeOptions = DEQUANTIZE_DEFAULTS): Transform {
const options = { ...DEQUANTIZE_DEFAULTS, ..._options } as Required<DequantizeOptions>;
return createTransform(NAME, (doc: Document): void => {
const logger = doc.getLogger();
for (const mesh of doc.getRoot().listMeshes()) {
for (const prim of mesh.listPrimitives()) {
dequantizePrimitive(prim, options);
}
}
doc.createExtension(MeshQuantization).dispose();
logger.debug(`${NAME}: Complete.`);
});
}
function dequantizePrimitive(prim: Primitive, options: Required<DequantizeOptions>): void {
for (const semantic of prim.listSemantics()) {
dequantizeAttribute(semantic, prim.getAttribute(semantic)!, options);
}
for (const target of prim.listTargets()) {
for (const semantic of target.listSemantics()) {
dequantizeAttribute(semantic, target.getAttribute(semantic)!, options);
}
}
}
function dequantizeAttribute(semantic: string, attribute: Accessor, options: Required<DequantizeOptions>): void {
if (!attribute.getArray()) return;
if (!options.pattern.test(semantic)) return;
if (attribute.getComponentSize() >= 4) return;
const srcArray = attribute.getArray()!;
const dstArray = new Float32Array(srcArray.length);
for (let i = 0, il = attribute.getCount(), el = [] as number[]; i < il; i++) {
el = attribute.getElement(i, el);
attribute.setArray(dstArray).setElement(i, el).setArray(srcArray);
}
attribute.setArray(dstArray).setNormalized(false);
}