From 8aa84c8c51caac0beaa483cb19b3cc089009c537 Mon Sep 17 00:00:00 2001 From: Don McCurdy Date: Fri, 11 Oct 2024 17:04:12 -0400 Subject: [PATCH] feat(extensions,functions): Allow encoding meshopt-compressed float32 accessors --- packages/cli/src/cli.ts | 6 ++--- .../src/ext-meshopt-compression/constants.ts | 1 + .../src/ext-meshopt-compression/encoder.ts | 6 +++++ .../meshopt-compression.ts | 6 ++++- packages/functions/src/meshopt.ts | 26 +++++++++---------- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts index b0f0b552e..a87438416 100755 --- a/packages/cli/src/cli.ts +++ b/packages/cli/src/cli.ts @@ -254,7 +254,7 @@ commands or using the scripting API. default: INSTANCE_DEFAULTS.min, }) .option('--meshopt-level ', 'Meshopt compression level.', { - validator: ['medium', 'high'], + validator: ['low', 'medium', 'high'], default: 'high', }) .option('--palette ', 'Creates palette textures and merges materials.', { @@ -344,7 +344,7 @@ commands or using the scripting API. const opts = options as { instance: boolean; instanceMin: number; - meshoptLevel: 'medium' | 'high'; + meshoptLevel: 'low' | 'medium' | 'high'; palette: boolean; paletteMin: number; simplify: boolean; @@ -859,7 +859,7 @@ ${underline('References')} .argument('', INPUT_DESC) .argument('', OUTPUT_DESC) .option('--level ', 'Compression level.', { - validator: ['medium', 'high'], + validator: ['low', 'medium', 'high'], default: 'high', }) .option('--quantize-position ', 'Precision for POSITION attributes.', { diff --git a/packages/extensions/src/ext-meshopt-compression/constants.ts b/packages/extensions/src/ext-meshopt-compression/constants.ts index 4f5b69536..e41146600 100644 --- a/packages/extensions/src/ext-meshopt-compression/constants.ts +++ b/packages/extensions/src/ext-meshopt-compression/constants.ts @@ -1,5 +1,6 @@ import type { GLTF, TypedArray } from '@gltf-transform/core'; +/** @deprecated Use 'filter' boolean instead. */ export enum EncoderMethod { QUANTIZE = 'quantize', FILTER = 'filter', diff --git a/packages/extensions/src/ext-meshopt-compression/encoder.ts b/packages/extensions/src/ext-meshopt-compression/encoder.ts index b7641dae4..f46074acd 100644 --- a/packages/extensions/src/ext-meshopt-compression/encoder.ts +++ b/packages/extensions/src/ext-meshopt-compression/encoder.ts @@ -139,6 +139,12 @@ export function getMeshoptFilter(accessor: Accessor, doc: Document): { filter: M .listParentEdges(accessor) .filter((edge) => !(edge.getParent() instanceof Root)); + // If filtering is enabled but the attribute is not quantized, do not filter, + // which would change the attribute's component type. + if (accessor.getComponentSize() > 2) { + return { filter: MeshoptFilter.NONE }; + } + for (const ref of refs) { const refName = ref.getName(); const refKey = (ref.getAttributes().key || '') as string; diff --git a/packages/extensions/src/ext-meshopt-compression/meshopt-compression.ts b/packages/extensions/src/ext-meshopt-compression/meshopt-compression.ts index ddaa776a3..cb8067e47 100644 --- a/packages/extensions/src/ext-meshopt-compression/meshopt-compression.ts +++ b/packages/extensions/src/ext-meshopt-compression/meshopt-compression.ts @@ -19,10 +19,14 @@ import type { MeshoptEncoder, MeshoptDecoder } from 'meshoptimizer'; const NAME = EXT_MESHOPT_COMPRESSION; interface EncoderOptions { + /** Whether to use meshopt filters, for more aggressive compression. Overrides 'method'. */ + filter?: boolean; + /** @deprecated Use 'filter' instead. */ method?: EncoderMethod; } const DEFAULT_ENCODER_OPTIONS: Required = { + filter: false, method: EncoderMethod.QUANTIZE, }; @@ -313,7 +317,7 @@ export class EXTMeshoptCompression extends Extension { const parentID = context.accessorUsageGroupedByParent.has(usage) ? getParentID(accessor) : null; const mode = getMeshoptMode(accessor, usage); const filter = - options.method === EncoderMethod.FILTER + (options.filter || options.method === EncoderMethod.FILTER) ? getMeshoptFilter(accessor, this.document) : { filter: MeshoptFilter.NONE }; const preparedAccessor = prepareAccessor(accessor, encoder, mode, filter); diff --git a/packages/functions/src/meshopt.ts b/packages/functions/src/meshopt.ts index 9077603e8..b13497fbf 100644 --- a/packages/functions/src/meshopt.ts +++ b/packages/functions/src/meshopt.ts @@ -7,7 +7,7 @@ import { assignDefaults, createTransform } from './utils.js'; export interface MeshoptOptions extends Omit { encoder: unknown; - level?: 'medium' | 'high'; + level?: 'low' | 'medium' | 'high'; } export const MESHOPT_DEFAULTS: Required> = { @@ -78,22 +78,22 @@ export function meshopt(_options: MeshoptOptions): Transform { encoder: encoder, target: 'size', }), - quantize({ - ...options, - pattern, - patternTargets, - quantizeNormal, - }), ); + if (options.level !== 'low') { + await document.transform( + quantize({ + ...options, + pattern, + patternTargets, + quantizeNormal, + }), + ); + } + document .createExtension(EXTMeshoptCompression) .setRequired(true) - .setEncoderOptions({ - method: - options.level === 'medium' - ? EXTMeshoptCompression.EncoderMethod.QUANTIZE - : EXTMeshoptCompression.EncoderMethod.FILTER, - }); + .setEncoderOptions({filter: options.level === 'high'}); }); }