Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use the pipeline tool #111

Closed
lllllleo42 opened this issue Apr 3, 2024 · 7 comments
Closed

How to use the pipeline tool #111

lllllleo42 opened this issue Apr 3, 2024 · 7 comments

Comments

@lllllleo42
Copy link

I want to use the pipeline tool to batch create tileset.json, but I can't find the tutorial. I can only find a step to define a pipeline JSON file
image

@javagl
Copy link
Contributor

javagl commented Apr 3, 2024

When you say

... to batch create tileset.json, ...

then it might be that the pipeline functionality is not what you're looking for. The pipeline function (as it was introduced several years ago aimed at performing a sequence of operations on each tile content of an existing tileset (e.g. to optimize each B3DM, and then ZIP it...).

When you say that you want to "batch create tileset.json", then this sounds like you wanted to call the createTilesetJson function for a set of input GLB files. Is that correct?

(If this is correct, then this functionality could probably be implemented with a few (very few) lines of code in a custom script, but I'd like to make sure that I understood this correctly...)

@lllllleo42
Copy link
Author

Thank you for answering my question. Sorry again for my poor English expression. Yes, your understanding is right. I wanted to call the createTilesetJson function for a set of input GLB files. However, I have too many glb files to input, making the command line too long, so I want to use some pipeline tools. Thanks again.

When you say that you want to "batch create tileset.json", then this sounds like you wanted to call the createTilesetJson function for a set of input GLB files. Is that correct?

@javagl
Copy link
Contributor

javagl commented Apr 4, 2024

I have too many glb files to input, making the command line too long, so I want to use some pipeline tools.

The createTilesetJson command can accept a directory as the --input parameter. So when you have a directory like C:\AllMyInputFiles that contains 1000 GLB files, then you can just say

npx 3d-tiles-tools createTilesetJson -i C:/AllMyInputFiles -o C:/AllMyInputFiles/tileset.json

and it will create a single tileset.json that refers to all the 1000 GLB files in that directory.

(Note that the structure of this tileset JSON will be really simple, and it could be possible to create a "better" one, with more information about what the GLB files are, and how they should be combined)


If you want to create one tileset.json file for each GLB, then you could of course run

npx 3d-tiles-tools createTilesetJson -i C:/AllMyInputFiles/input0001.glb -o C:/AllMyInputFiles/tileset0001.json
npx 3d-tiles-tools createTilesetJson -i C:/AllMyInputFiles/input0002.glb -o C:/AllMyInputFiles/tileset0002.json
npx 3d-tiles-tools createTilesetJson -i C:/AllMyInputFiles/input0003.glb -o C:/AllMyInputFiles/tileset0003.json
....

1000 times - but .... you shouldn't do this 🙂 If this is the goal, then you could solve this with a small, custom script (and I'll post an example here if this is what you're trying to do...)

@lllllleo42
Copy link
Author

Thanks. Actually, what I'm trying to do is converting many glb files to a 3dtiles file. However, I need to assign latitude and longitude coordinates to each glb file, Otherwise, there will be many models overlapping in the same location. So I came up with a stupid but simple solution, which is to use the createTilesetJson function for each glb file and generate tileset.json separately. And finally, merg these tileset into a single one. I guess it's kind of stupid😥Thanks again for answering my questions.

@javagl
Copy link
Contributor

javagl commented Apr 7, 2024

It's not stupid. It sounds like a reasonable use-case, and could be a natural extension of the functionality that is already offered by createTilesetJson.

But when adding a new functionality, then one should have a clear idea about the degrees of freedom, and what this function can or cannot do. Right now, the createTilesetJson is targeted at creating a very simple tileset.json for one or more GLB files. Assigning different positions to the GLBs is not covered by that.

If the desired funcitonality was supposed to be added, then I'd have to think this through more thoroughly. And this request does have some overlap to #84 .

In both cases, one important question is:

Where does the latitude/longitude/height information for each model come from?

So you have your directory with GLB files, like exampleA.glb, exampleB.glb, exampleC.glb.... And each of them has a different latitude/longitude/height. So the pseudocode(!!!) of the function that you would need could be

magic.addContent("exampleA.glb", 35, 140, 10);
magic.addContent("exampleB.glb", 37, 135, 30);
magic.addContent("exampleC.glb", 36, 142, 01);
...
tileset = magic.buildThat();

But this works well only for "few" files. When there are many files (hundreds), then the latitude/longitude/height information is probably contained in some CSV file or some JSON structure (maybe something that is queried via a REST API or so...)


I just started drafting some tests for this.

NOTE: During thest tests, I noticed that #112 . This is fixed via #113 , but this is not merged yet.

The approach that you described would probably work, in principle:

  • Use the createTilesetJson functionality to create one tileset.json for each input file (using the proper cartographic position)
  • Use the merge functionality to create one tileset that refers to each of them as external tilesets
  • Use the combine functionality to create a single tileset

This is drafted here.

NOTE: This does use the "library-level" functionality, and not the command line functionality. All this is not "public" yet. This is only a DRAFT.

import fs from "fs";
import path from "path";

import { TilesetJsonCreator } from "./src/tools/tilesetProcessing/TilesetJsonCreator";
import { TilesetOperations } from "./src/tools/tilesetProcessing/TilesetOperations";
import { Paths } from "./src/base";

const baseDir = "./input";
const glbDir = path.resolve(baseDir, "glbFiles");
const tilesetsBaseDir = path.resolve(baseDir, "tilesets");
const mergedFileName = path.resolve(baseDir, "merged/tileset-merged.json");
const combinedFileName = path.resolve(
  baseDir,
  "combined/tileset-combined.json"
);
const inputs = [
  {
    fileName: "exampleA.glb",
    lonLatHeightDegrees: [-75.15, 39.94, 50.0],
  },
  {
    fileName: "exampleB.glb",
    lonLatHeightDegrees: [-75.1502, 39.94, 50.2],
  },
  {
    fileName: "exampleC.glb",
    lonLatHeightDegrees: [-75.1504, 39.94, 50.4],
  },
];

async function run() {
  const overwrite = true;

  const tilesetFileNames: string[] = [];
  for (const input of inputs) {
    const fileName = input.fileName;
    console.log("Create tileset JSON for " + fileName);

    const inputGlbName = path.resolve(glbDir, fileName);
    const tilesetName = "tileset-" + Paths.replaceExtension(fileName, "");
    const tilesetDir = path.resolve(tilesetsBaseDir, tilesetName);
    const outputGlbName = path.resolve(tilesetDir, fileName);
    Paths.ensureDirectoryExists(tilesetDir);
    fs.copyFileSync(inputGlbName, outputGlbName);

    const tileset = await TilesetJsonCreator.createTilesetFromContents(
      tilesetDir,
      [fileName]
    );

    console.log("Assigning position for " + fileName);
    const cartographicPositionDegrees = input.lonLatHeightDegrees;
    const transform =
      TilesetJsonCreator.computeTransformFromCartographicPositionDegrees(
        cartographicPositionDegrees
      );
    tileset.root.transform = transform;
    const tilesetFileName = path.resolve(tilesetDir, "tileset.json");

    console.log("Writing " + tilesetFileName + " for content file " + fileName);
    fs.writeFileSync(tilesetFileName, JSON.stringify(tileset, null, 2));
    tilesetFileNames.push(tilesetFileName);
  }

  console.log("Merging...");
  await TilesetOperations.merge(tilesetFileNames, mergedFileName, overwrite);

  console.log("Combining...");
  await TilesetOperations.combine(mergedFileName, combinedFileName, overwrite);

  console.log("Done, output at " + combinedFileName);
}

run();

I tried this out, with some example GLB files, and it should work in principle:

Cesium Multiple GLB Tileset

But ... this is quirky: It should not be necessary to apply a sequence of three operations, with lots of intermediate steps and input/output files and directories, just to accomplish this task.

There should be a simpler functionality for that. But I'll have to think about how this could be offered sensibly. For example, how to define the cartographic position that each GLB should have. It wouldn't make sense to try to offer this as a pure command-line function. There has to be some sort of input file (CSV or JSON) that defines the position for each GLB. And this means that the implementation should be carefully thought through.

(One could say that we'll have to get our ducks in a row before implementing that 😁 )

@lllllleo42
Copy link
Author

Thanks!!!It really helped me a lot😀

@javagl
Copy link
Contributor

javagl commented May 15, 2024

Since the last part is no longer related to the pipeline function, and boiled down to a somewhat specific (but potentially very useful) functionality, I tried to summarize this in #130

@javagl javagl closed this as completed May 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants