Skip to content

Commit

Permalink
Try to upgrade CMPT to GLB when target version is 1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
javagl committed Apr 19, 2024
1 parent 03e5dc2 commit 9a443bf
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 2 deletions.
58 changes: 58 additions & 0 deletions src/tools/contentProcessing/GltfTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ import draco3d from "draco3d";
import { MeshoptDecoder } from "meshoptimizer";
import { MeshoptEncoder } from "meshoptimizer";

import { Document } from "@gltf-transform/core";
import { Logger } from "@gltf-transform/core";
import { Transform } from "@gltf-transform/core";
import { NodeIO } from "@gltf-transform/core";

import { prune } from "@gltf-transform/functions";
import { unpartition } from "@gltf-transform/functions";

import { ALL_EXTENSIONS } from "@gltf-transform/extensions";

import { EXTStructuralMetadata } from "../../gltf-extensions";
Expand Down Expand Up @@ -79,4 +84,57 @@ export class GltfTransform {
const outputGlb = await io.writeBinary(document);
return Buffer.from(outputGlb);
}

/**
* Combine all scenes in the given document into one.
*
* This will take the first scene, declare it as the default scene,
* attach the nodes from all other scenes to this one, and dispose
* the other scenes.
*
* @param document - The glTF-Transform document
*/
private static async combineScenes(document: Document) {
const root = document.getRoot();
const scenes = root.listScenes();
if (scenes.length > 0) {
const combinedScene = scenes[0];
root.setDefaultScene(combinedScene);
for (let s = 1; s < scenes.length; s++) {
const otherScene = scenes[s];
const children = otherScene.listChildren();
for (const child of children) {
combinedScene.addChild(child);
otherScene.removeChild(child);
}
otherScene.dispose();
}
}
document.setLogger(new Logger(Logger.Verbosity.WARN));
await document.transform(prune());
}

/**
* Creates a single glTF Transform document from the given GLB buffers.
*
* This will create a document with a single scene that contains all
* nodes that have been children of any scene in the given input
* GLBs.
*
* @param inputGlbBuffers - The buffers containing GLB data
* @returns The merged document
*/
static async merge(inputGlbBuffers: Buffer[]): Promise<Document> {
// Create one document from each buffer and merge them
const io = await GltfTransform.getIO();
const mergedDocument = new Document();
for (const inputGlbBuffer of inputGlbBuffers) {
const inputDocument = await io.readBinary(inputGlbBuffer);
mergedDocument.merge(inputDocument);
}
// Combine all scenes into one
await GltfTransform.combineScenes(mergedDocument);
await mergedDocument.transform(unpartition());
return mergedDocument;
}
}
21 changes: 21 additions & 0 deletions src/tools/migration/TileFormatsMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Document } from "@gltf-transform/core";
import { TileFormatsMigrationPnts } from "./TileFormatsMigrationPnts";
import { TileFormatsMigrationB3dm } from "./TileFormatsMigrationB3dm";
import { TileFormatsMigrationI3dm } from "./TileFormatsMigrationI3dm";
import { TileFormatsMigrationCmpt } from "./TileFormatsMigrationCmpt";

/**
* Methods for converting "legacy" tile formats into glTF assets
Expand Down Expand Up @@ -57,6 +58,26 @@ export class TileFormatsMigration {
);
}

/**
* Convert the given CMPT data into a single glTF asset
*
* @param cmptBuffer - The CMPT buffer
* @param externalGlbResolver - A function that will be used to resolve
* external GLB data if the CMPT contains I3DM that use
* `header.gltfFormat=0` (meaning that the payload is not GLB data,
* but only a GLB URI).
* @returns The GLB buffer
*/
static async convertCmptToGlb(
cmptBuffer: Buffer,
externalGlbResolver: (uri: string) => Promise<Buffer | undefined>
): Promise<Buffer> {
return await TileFormatsMigrationCmpt.convertCmptToGlb(
cmptBuffer,
externalGlbResolver
);
}

/**
* Apply the given RTC_CENTER to the given glTF-Transform document,
* by inserting a new root node that carries the given RTC_CENTER
Expand Down
83 changes: 83 additions & 0 deletions src/tools/migration/TileFormatsMigrationCmpt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { ContentDataTypeRegistry } from "../../base";
import { ContentDataTypes } from "../../base";

import { TileFormats } from "../../tilesets";

import { GltfTransform } from "../contentProcessing/GltfTransform";

import { TileFormatsMigration } from "./TileFormatsMigration";

import { Loggers } from "../../base";
const logger = Loggers.get("migration");

/**
* Methods for converting CMPT tile data into GLB
*
* @internal
*/
export class TileFormatsMigrationCmpt {
/**
* Convert the given CMPT data into a glTF asset
*
* @param cmptBuffer - The CMPT buffer
* @param externalGlbResolver - A function that will be used to resolve
* external GLB data if the CMPT contains I3DM that use
* `header.gltfFormat=0` (meaning that the payload is not GLB data,
* but only a GLB URI).
* @returns The GLB buffer
* @throws TileFormatError If the CMPT contained I3DM with an external
* GLB URI * that could not resolved by the given resolver
*/
static async convertCmptToGlb(
cmptBuffer: Buffer,
externalGlbResolver: (uri: string) => Promise<Buffer | undefined>
): Promise<Buffer> {
const compositeTileData = TileFormats.readCompositeTileData(cmptBuffer);
const innerTileBuffers = compositeTileData.innerTileBuffers;

const innerTileGlbs: Buffer[] = [];
for (const innerTileBuffer of innerTileBuffers) {
const innerTileType = await ContentDataTypeRegistry.findType(
"",
innerTileBuffer
);
if (innerTileType === ContentDataTypes.CONTENT_TYPE_PNTS) {
logger.trace("Converting inner PNTS tile to GLB...");
const innerTileGlb = await TileFormatsMigration.convertPntsToGlb(
innerTileBuffer
);
innerTileGlbs.push(innerTileGlb);
} else if (innerTileType === ContentDataTypes.CONTENT_TYPE_B3DM) {
logger.trace("Converting inner B3DM tile to GLB...");
const innerTileGlb = await TileFormatsMigration.convertB3dmToGlb(
innerTileBuffer
);
innerTileGlbs.push(innerTileGlb);
} else if (innerTileType === ContentDataTypes.CONTENT_TYPE_I3DM) {
logger.trace("Converting inner I3DM tile to GLB...");
const innerTileGlb = await TileFormatsMigration.convertI3dmToGlb(
innerTileBuffer,
externalGlbResolver
);
innerTileGlbs.push(innerTileGlb);
} else if (innerTileType === ContentDataTypes.CONTENT_TYPE_CMPT) {
logger.trace("Converting inner CMPT tile to GLB...");
const innerTileGlb = await TileFormatsMigration.convertCmptToGlb(
innerTileBuffer,
externalGlbResolver
);
innerTileGlbs.push(innerTileGlb);
} else {
logger.warn(
"Unknown type for inner tile of CMPT: " +
innerTileType +
" - ignoring"
);
}
}
const document = await GltfTransform.merge(innerTileGlbs);
const io = await GltfTransform.getIO();
const glb = await io.writeBinary(document);
return Buffer.from(glb);
}
}
61 changes: 59 additions & 2 deletions src/tools/tilesetProcessing/TilesetUpgrader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export class TilesetUpgrader {
upgradePntsToGlb: false,
upgradeB3dmToGlb: false,
upgradeI3dmToGlb: false,
upgradeCmptToGlb: false,
};
return options;
}
Expand All @@ -103,6 +104,7 @@ export class TilesetUpgrader {
upgradePntsToGlb: true,
upgradeB3dmToGlb: true,
upgradeI3dmToGlb: true,
upgradeCmptToGlb: true,
};
return options;
}
Expand Down Expand Up @@ -216,6 +218,11 @@ export class TilesetUpgrader {
return Paths.replaceExtension(uri, ".glb");
}
}
if (this.upgradeOptions.upgradeCmptToGlb) {
if (Paths.hasExtension(uri, ".cmpt")) {
return Paths.replaceExtension(uri, ".glb");
}
}
return uri;
};

Expand Down Expand Up @@ -263,11 +270,12 @@ export class TilesetUpgrader {
): Promise<TilesetEntry> => {
if (type === ContentDataTypes.CONTENT_TYPE_PNTS) {
return this.processEntryPnts(sourceEntry);
}
if (type === ContentDataTypes.CONTENT_TYPE_B3DM) {
} else if (type === ContentDataTypes.CONTENT_TYPE_B3DM) {
return this.processEntryB3dm(sourceEntry);
} else if (type === ContentDataTypes.CONTENT_TYPE_I3DM) {
return this.processEntryI3dm(sourceEntry);
} else if (type === ContentDataTypes.CONTENT_TYPE_CMPT) {
return this.processEntryCmpt(sourceEntry);
} else if (type == ContentDataTypes.CONTENT_TYPE_TILESET) {
return this.processEntryTileset(sourceEntry);
}
Expand Down Expand Up @@ -394,6 +402,55 @@ export class TilesetUpgrader {
return targetEntry;
};

/**
* Process the given tileset (content) entry that contains CMPT,
* and return the result.
*
* @param sourceEntry - The source entry
* @returns The processed entry
*/
private processEntryCmpt = async (
sourceEntry: TilesetEntry
): Promise<TilesetEntry> => {
const sourceKey = sourceEntry.key;
const sourceValue = sourceEntry.value;
let targetKey = sourceKey;
let targetValue = sourceValue;
if (this.upgradeOptions.upgradeCmptToGlb) {
logger.debug(` Upgrading CMPT to GLB for ${sourceKey}`);

targetKey = this.processContentUri(sourceKey);

// Define the resolver for external GLB files in CMPT files:
// It will look up the entry using the 'tilesetProcessor'
const externalGlbResolver = async (
uri: string
): Promise<Buffer | undefined> => {
if (!this.tilesetProcessor) {
return undefined;
}
const externalGlbEntry = await this.tilesetProcessor.fetchSourceEntry(
uri
);
if (!externalGlbEntry) {
return undefined;
}
return externalGlbEntry.value;
};
targetValue = await TileFormatsMigration.convertCmptToGlb(
sourceValue,
externalGlbResolver
);
} else {
logger.debug(` Not upgrading ${sourceKey} (disabled via option)`);
}
const targetEntry = {
key: targetKey,
value: targetValue,
};
return targetEntry;
};

/**
* Process the given tileset (content) entry that contains the
* JSON of an external tileset, and return the result.
Expand Down
3 changes: 3 additions & 0 deletions src/tools/tilesetProcessing/upgrade/TilesetUpgradeOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ export type TilesetUpgradeOptions = {
// Whether attempts should be made to convert I3DM files to GLB
// with metadata
upgradeI3dmToGlb: boolean;

// Whether attempts should be made to convert CMPT files to GLB
upgradeCmptToGlb: boolean;
};

0 comments on commit 9a443bf

Please sign in to comment.