Creating b3dm results in loss of original attributes
Hello developer, I would like to convert a GLB model with attribute information to b3DM format, but after the conversion is completed, I found that the b3DM model is missing attribute information. I would like to know how to remedy this. Here is my input command:
npx 3d-tiles-tools glbToB3dm -i ./test.glb -o ./test.b3dm
I also used to convert glb to obj before doing this, but the result still did not contain any attribute information,I have reviewed relevant materials and found that two additional tables are needed to store attribute information and quantity information:batchtable and featuretable.And the batch_ID attribute needs to be added to the model to be converted,I don't quite understand how to operate it. If you could answer, I would greatly appreciate it. Thank you
This is the converted attribute information, and it can be seen that the data has been lost:
I might need a few more details about the goal that you are trying to accomplish.
But first, a few general remarks:
The B3DM format is considered to be a "legacy" format. There should hardly be a reason to convert a GLB file into B3DM. Nearly everything that can be done with B3DM can also be done with GLB (in doubt, using some of the glTF Metadata extensions).
The glbToB3dm command does not involve a lot of functionality in that regard. It is not really a "conversion" in the most narrow sense. It only creates a B3DM with an empty batch- and feature table, and the GLB (Binary glTF) appended as the actual payload, as shown in the diagram of the specification.
Regarding your specific question: I'm wondering what 'attribute information' you are referring to. (That's hard to guess from the screenshot). If the glTF/GLB contains additional data in vertex attributes, then this data should be transported to CesiumJS as it is - but CesiumJS will not necessarily know what to do with this data. If the glTF/GLB contains additional data in form of the glTF Metadata Extensions (like EXT_structural_metadata, then it might be that CesiumJS will not process this data any more when the GLB is wrapped into a B3DM. In any case, the glbToB3dm will not convert this data into a batch table or so.
If you could provide an example GLB file and/or more detailed information about your goal, then we can investigate how this goal could be accomplished.
我可能需要更多关于你试图实现的目标的细节。
但首先,我们要说几句一般性的话:
B3DM 格式被认为是“传统”格式。几乎没有理由将 GLB 文件转换为 B3DM。几乎所有可以用 B3DM 完成的事情也可以用 GLB 完成(毫无疑问,使用一些 glTF 元数据扩展)。
该命令在这方面不涉及很多功能。这并不是最狭义的“转变”。它仅创建一个具有空批处理和特征表的 B3DM,并将 GLB(二进制 glTF)附加为实际有效负载,如规范图所示。
glbToB3dm关于您的具体问题:我想知道您指的是什么“属性信息”。(从截图中很难猜到)。如果 glTF/GLB 在_顶点属性_中包含其他数据,则这些数据应按原样传输到 CesiumJS - 但 CesiumJS 不一定知道如何处理这些数据。如果 glTF/GLB 包含 glTF 元数据扩展形式的其他数据(如 ,那么当 GLB 包装到 B3DM 中时,CesiumJS 可能不会再处理这些数据。在任何情况下,都不会将此数据转换为批处理表左右。
glbToB3dm如果您能提供一个示例 GLB 文件和/或有关您的目标的更多详细信息,那么我们可以研究如何实现此目标。
I might need a few more details about the goal that you are trying to accomplish.
But first, a few general remarks:
The B3DM format is considered to be a "legacy" format. There should hardly be a reason to convert a GLB file into B3DM. Nearly everything that can be done with B3DM can also be done with GLB (in doubt, using some of the glTF Metadata extensions).
The
glbToB3dmcommand does not involve a lot of functionality in that regard. It is not really a "conversion" in the most narrow sense. It only creates a B3DM with an empty batch- and feature table, and the GLB (Binary glTF) appended as the actual payload, as shown in the diagram of the specification.Regarding your specific question: I'm wondering what 'attribute information' you are referring to. (That's hard to guess from the screenshot). If the glTF/GLB contains additional data in vertex attributes, then this data should be transported to CesiumJS as it is - but CesiumJS will not necessarily know what to do with this data. If the glTF/GLB contains additional data in form of the glTF Metadata Extensions (like
EXT_structural_metadata, then it might be that CesiumJS will not process this data any more when the GLB is wrapped into a B3DM. In any case, theglbToB3dmwill not convert this data into a batch table or so.If you could provide an example GLB file and/or more detailed information about your goal, then we can investigate how this goal could be accomplished.
Thank you for your reply. As you said, a complete b3dm requires a combination of featuretable, batchtable, and glb. The commands I execute also lack featuretable and batchtable, so the program uses the default blank table. Therefore, the attribute information I save in batchtable cannot correspond to glb. What should I do next to bind the attributes in the batchtable to GLB, thus forming a complete b3DM? Thank you. Here are my GLB model and the batchtable and featuretable tables (the data in the tables was written by myself, I think it should be correct) Uploading barrel.b3dm.batchTable.zip…
Excuse me, I used Threejs for model presentation and did not use Cesiumjs
I looks like the Upload did not work.
When you already have a batch table and a feature table (as JSON), and want to combine this with the GLB, then this might be possible with a small, custom script that uses the 3D Tiles Tools as a library. (But note that the GLB will likely have to contain a Batch ID attribute, so it's hard to say whether the result is what you'd expect).
I'm sorry, there is no corresponding id attribute in the glb I contain. If I need to add it one by one, I think it will be very time-consuming. If I convert the glb file to obj format, do I still need to add the id attribute. Here are the files that I failed to upload before. barrel.b3dm.batchTable.zip
Fortunately, the GLB already does contain the batch ID data - here is one of the meshes of the GLB file:
"name" : "Barrel.013_Cylinder.021",
"primitives" : [
{
"attributes" : {
"POSITION" : 0,
"NORMAL" : 1,
"TEXCOORD_0" : 2,
"_BATCHID" : 3
},
"indices" : 4,
"material" : 0,
"mode" : 4
}
]
(It looks like this GLB was actually extracted from an existing B3DM file. If your goal is to modify the data that is contained in the Batch- or Feature Table of an existing B3DM file, then this should be possible, relatively easily, with the 3D Tiles Tools as well...)
Note: The GLB file is actually invalid. When you drag-and-drop this file into the glTF Validator at https://github.khronos.org/glTF-Validator/ , then it will report several errors.
For now, it looks like it could still work, but ... there are no guarantees that this will work in all cases. There might be rendering errors when you try to load invalid data.
However, you can create a new B3DM file from this. And for that, you can use the 3D Tiles Tools as a library. Technically, it would be possible to do this with the NPM package - but this is not officially released as a library, so I'll summarize the process here, based on the Developer Setup:
-
Clone this repository and run
npm install, as described in the Developer Setup -
Add the following file as
CreateB3dm.tsin the root directory:
import fs from "fs";
import { TileFormats } from "./src";
async function run() {
const glbFileName = "./data/issue115/barrel.b3dm.glb";
const featureTableFileName = "./data/issue115/barrel.b3dm.featureTable.json";
const batchTableFileName = "./data/issue115/barrel.b3dm.batchTable.json";
const b3dmFileName = "./data/issue115/barrel-RESULT.b3dm";
const glbData = fs.readFileSync(glbFileName);
const featureTableJson = JSON.parse(
fs.readFileSync(featureTableFileName).toString()
);
const featureTableBinary = undefined;
const batchTableJson = JSON.parse(
fs.readFileSync(batchTableFileName).toString()
);
const batchTableBinary = undefined;
const b3dmTileData = TileFormats.createB3dmTileDataFromGlb(
glbData,
featureTableJson,
featureTableBinary,
batchTableJson,
batchTableBinary
);
const b3dmData = TileFormats.createTileDataBuffer(b3dmTileData);
fs.writeFileSync(b3dmFileName, b3dmData);
}
run();
(Adjust the directories as needed)
- Run
npx ts-node .\CreateB3dm.ts
This will read the files that you have provided in the ZIP file, and create new B3DM data from these files, and write it out as barrel-RESULT.b3dm.
You can then, for example, use the createTilesetJson command of the 3D Tiles Tools to create a small tileset JSON from this, and load it into a simple sandcastle. The result will be the following:
Showing that it does load the data, and it shows the batch table data for each clicked barrel.
Here is the result (including the tileset JSON and the sandcastle) just for convenience:
Fortunately, the GLB already does contain the batch ID data - here is one of the
meshesof the GLB file:"name" : "Barrel.013_Cylinder.021", "primitives" : [ { "attributes" : { "POSITION" : 0, "NORMAL" : 1, "TEXCOORD_0" : 2, "_BATCHID" : 3 }, "indices" : 4, "material" : 0, "mode" : 4 } ](It looks like this GLB was actually extracted from an existing B3DM file. If your goal is to modify the data that is contained in the Batch- or Feature Table of an existing B3DM file, then this should be possible, relatively easily, with the 3D Tiles Tools as well...)
Note: The GLB file is actually invalid. When you drag-and-drop this file into the glTF Validator at https://github.khronos.org/glTF-Validator/ , then it will report several errors.
For now, it looks like it could still work, but ... there are no guarantees that this will work in all cases. There might be rendering errors when you try to load invalid data.
However, you can create a new B3DM file from this. And for that, you can use the 3D Tiles Tools as a library. Technically, it would be possible to do this with the NPM package - but this is not officially released as a library, so I'll summarize the process here, based on the Developer Setup:
Clone this repository and run
npm install, as described in the Developer SetupAdd the following file as
CreateB3dm.tsin the root directory:import fs from "fs"; import { TileFormats } from "./src"; async function run() { const glbFileName = "./data/issue115/barrel.b3dm.glb"; const featureTableFileName = "./data/issue115/barrel.b3dm.featureTable.json"; const batchTableFileName = "./data/issue115/barrel.b3dm.batchTable.json"; const b3dmFileName = "./data/issue115/barrel-RESULT.b3dm"; const glbData = fs.readFileSync(glbFileName); const featureTableJson = JSON.parse( fs.readFileSync(featureTableFileName).toString() ); const featureTableBinary = undefined; const batchTableJson = JSON.parse( fs.readFileSync(batchTableFileName).toString() ); const batchTableBinary = undefined; const b3dmTileData = TileFormats.createB3dmTileDataFromGlb( glbData, featureTableJson, featureTableBinary, batchTableJson, batchTableBinary ); const b3dmData = TileFormats.createTileDataBuffer(b3dmTileData); fs.writeFileSync(b3dmFileName, b3dmData); } run();(Adjust the directories as needed)
- Run
npx ts-node .\CreateB3dm.tsThis will read the files that you have provided in the ZIP file, and create new B3DM data from these files, and write it out as
barrel-RESULT.b3dm.
You can then, for example, use the
createTilesetJsoncommand of the 3D Tiles Tools to create a small tileset JSON from this, and load it into a simple sandcastle. The result will be the following:
Showing that it does load the data, and it shows the batch table data for each clicked barrel.
Here is the result (including the tileset JSON and the sandcastle) just for convenience:
Yes, you guessed it right. This is indeed what I extracted from a b3DM file. Thank you for sending the file. I am planning to use Threejs to implement this process. Do you have any better insights on how to add the corresponding batchid in the glb file? Of course, I am still very grateful for your help!
The Batch ID already is contained in the GLB file (because it was apparently just extracted from a B3DM)
If such a GLB file does not contain a Batch ID, then you'd have to add this manually, and that could be pretty difficult, depending on the model. You could try to do this with glTF-Transform or with the 3D Tiles Tools or with Blender, but it would involve some coding and manual work in all cases...
The reason for my question (whether you extracted the GLB from an existing B3DM file) mainly was that you could also do this completely programmatically: The code that I showed you uses the createB3dmTileDataFromGlb to create the B3DM data from the given GLB and the batch- and feature table. But when you already have a B3DM file, then you could use TileFormats.readTileData(b3dmDataBuffer) to read the tile data, then directly modify the batch- and feature table, and write out the modified B3DM data, without having to write the GLB- and JSON files. It could basically happen "in one step". But the details here will probably depend on your intended workflow.
Thank you so much. I think I know where to go next
I assume that there are no more actionable items here right now. If there are further questions, re-open this (or open a new) issue.