Skip to content

Commit

Permalink
fix(functions): Ensure quantize() creates required instance TRS attri…
Browse files Browse the repository at this point in the history
…butes for EXT_mesh_gpu_instancing
  • Loading branch information
donmccurdy committed Dec 17, 2024
1 parent 3b5b616 commit 7c02568
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions packages/functions/src/quantize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,13 @@ export function quantize(_options: QuantizeOptions = QUANTIZE_DEFAULTS): Transfo
}

function quantizePrimitive(
doc: Document,
document: Document,
prim: Primitive | PrimitiveTarget,
nodeTransform: VectorTransform<vec3>,
options: Required<QuantizeOptions>,
): void {
const isTarget = prim instanceof PrimitiveTarget;
const logger = doc.getLogger();
const logger = document.getLogger();

for (const semantic of prim.listSemantics()) {
if (!isTarget && !options.pattern.test(semantic)) continue;
Expand Down Expand Up @@ -280,7 +280,7 @@ function getNodeTransform(volume: bbox): VectorTransform<vec3> {
}

/** Applies corrective scale and offset to nodes referencing a quantized Mesh. */
function transformMeshParents(doc: Document, mesh: Mesh, nodeTransform: VectorTransform<vec3>): void {
function transformMeshParents(document: Document, mesh: Mesh, nodeTransform: VectorTransform<vec3>): void {
const transformMatrix = fromTransform(nodeTransform);
for (const parent of mesh.listParents()) {
if (!(parent instanceof Node)) continue;
Expand All @@ -297,13 +297,13 @@ function transformMeshParents(doc: Document, mesh: Mesh, nodeTransform: VectorTr

const batch = parent.getExtension<InstancedMesh>('EXT_mesh_gpu_instancing');
if (batch) {
parent.setExtension('EXT_mesh_gpu_instancing', transformBatch(batch, nodeTransform));
parent.setExtension('EXT_mesh_gpu_instancing', transformBatch(document, batch, nodeTransform));
continue;
}

let targetNode: Node;
if (isParentNode || isAnimated) {
targetNode = doc.createNode('').setMesh(mesh);
targetNode = document.createNode('').setMesh(mesh);
parent.addChild(targetNode).setMesh(null);
animChannels
.filter((channel) => channel.getTargetPath() === WEIGHTS)
Expand Down Expand Up @@ -333,21 +333,34 @@ function transformSkin(skin: Skin, nodeTransform: VectorTransform<vec3>): Skin {
}

/** Applies corrective scale and offset to GPU instancing batches. */
function transformBatch(batch: InstancedMesh, nodeTransform: VectorTransform<vec3>): InstancedMesh {
function transformBatch(document: Document, batch: InstancedMesh, nodeTransform: VectorTransform<vec3>): InstancedMesh {
if (!batch.getAttribute('TRANSLATION') && !batch.getAttribute('ROTATION') && !batch.getAttribute('SCALE')) {
return batch;
}

batch = batch.clone(); // quantize() does cleanup.
const instanceTranslation = batch.getAttribute('TRANSLATION')?.clone();

let instanceTranslation = batch.getAttribute('TRANSLATION')?.clone();
const instanceRotation = batch.getAttribute('ROTATION')?.clone();
const instanceScale = batch.getAttribute('SCALE')?.clone();
let instanceScale = batch.getAttribute('SCALE')?.clone();

const tpl = (instanceTranslation || instanceRotation || instanceScale)!;

const T_IDENTITY = [0, 0, 0] as vec3;
const R_IDENTITY = [0, 0, 0, 1] as vec4;
const S_IDENTITY = [1, 1, 1] as vec3;

// Transformed batch may now require instance translation or scale.
// See: https://github.com/donmccurdy/glTF-Transform/issues/1584

if (!instanceTranslation && nodeTransform.offset) {
instanceTranslation = document.createAccessor().setType('VEC3').setArray(makeArray(tpl.getCount(), T_IDENTITY));
}

if (!instanceScale && nodeTransform.scale) {
instanceScale = document.createAccessor().setType('VEC3').setArray(makeArray(tpl.getCount(), S_IDENTITY));
}

const t = [0, 0, 0] as vec3;
const r = [0, 0, 0, 1] as vec4;
const s = [1, 1, 1] as vec3;
Expand Down Expand Up @@ -608,3 +621,14 @@ function fromTransform(transform: VectorTransform<vec3>): mat4 {
function clamp(value: number, range: vec2): number {
return Math.min(Math.max(value, range[0]), range[1]);
}

function makeArray(elementCount: number, initialElement: vec2 | vec3 | vec4) {
const elementSize = initialElement.length;
const array = new Float32Array(elementCount * elementSize);

for (let i = 0; i < elementCount; i++) {
array.set(initialElement, i * elementSize);
}

return array;
}

0 comments on commit 7c02568

Please sign in to comment.