Which part of .b3dm contains the position property?

Hello everyone
I am interested in 3d-tiles spec and learning tile formats now. It is really an excellent method to organize 3d models.

However, I am confused when learning .b3dm format and want to know which part of .b3dm actually contains the position property.

In other words, how does .b3dm locate models in the right longitude and latitude?

Is it in batch table, binary glTF or other parts of the file. Or even other files?

Looking forward to your reply.




Hi Chris,

The position of the model is typically in the glTF itself. There are a few options:

  • the vertex data itself is already geolocated
  • the glTF contains a node that transforms the model to a longitude/latitude
  • the glTF uses the CESIUM_RTC extension. However this only applies a translation and not a rotation.
    And then one other option is to add a transform to the tile in the tileset.json file. This feature is currently in progress here and here.

Thanks, Sean
That helps a lot.

Since the gltf contains the longitude and latitude, how can I read these information?

In the example data, the glTF is binary and unreadable.

Is there a tool to interpret the binary part into readable string or something easy to find the longitute and latitude?


在 2016年8月18日星期四 UTC+8下午10:58:49,Sean Lilley写道:

Or can you tell me which property in the glTF contains the longitude and latitude.
That will be really helpful.

在 2016年8月18日星期四 UTC+8下午10:58:49,Sean Lilley写道:

The glTF doesn’t have the longitude and latitude exactly, but in some cases it may have a 4x4 matrix that transform it.(like in option 2 above) . Really the best place to get the longitude and latitude would be from the tileset.json, which defines the bounding volumes. Many of the example tilesets will have a boundingVolume.region property that gives you the [west longitude, south latitude, east longitude, north latitude, minHeight, maxHeight], which you can easily get the center longitude and latitude from.

Thanks Sean, your reply really helps me a lot.

在 2016年8月22日星期一 UTC+8下午9:24:29,Sean Lilley写道:

Hi Sean,

I am now doing experiments using the tileset data in Specs\Data\Cesium3DTiles\Tilesets\Tileset.

My aim is to move the whole models to another location.

For example, I mius the longitude and latitude of the center point by 5 degrees, and use the new center to do the following steps.

To move the tiles, I have done the following steps:

  1. I changed the boundingVolume.region properties of both parent tile and children in tileset.json. (Even the properties)

  2. Then I modified the extensions.CESIUM_RTC.center property into my new ECEF coordinates in all the five .b3dm files (parent, ll, lr, ul, ur).

(I use this website to transform the coordinates: http://www.nevaridge.com/georeferencing-tools.php)

Now when I load the tileset into Sandcastle of 3d-tiles branch, I can see the boundingRectangle (red and blue), and there is no error occurring.

The problem is the models can not be loaded or displayed.

Am I missing some points? OR my idea is totally wrong.

any help appreciated.


在 2016年8月22日星期一 UTC+8下午9:24:29,Sean Lilley写道:

These steps won’t work for that specific tileset. The model vertex data has the longitude and latitude baked in, so trying to update the CESIUM_RTC not have an effect, besides positioning the models really far from away. Also modifying the bounding volumes does not move the content, the purpose of the bounding volumes is more for describing the content rather than moving it. Overall I think trying to re-position any of the example tilesets may be difficult to do and it’s better to try to build a tileset from scratch. We have a repo that we are working on to make it easier for people to create tilesets, but it’s not quite ready yet: https://github.com/AnalyticalGraphicsInc/3d-tiles-tools.

You may be interested in checking out this sample tileset in our 3d-tiles-samples repo: https://github.com/AnalyticalGraphicsInc/3d-tiles-samples/tree/master/tilesets/TilesetWithDiscreteLOD. To move the dragon around it should be as easy as changing the transform property of tileset.json. In order to run this tileset though you will need to be on the 3d-tiles-transform branch.

Hello Sean,
I am now building a tileset from scratch by myself.

I do the following steps:

  1. I wrote a tileset.json with only one root tile, there is a parent.b3dm in the content.

  2. I transform my models (four cubes exported from sketchup) into binary glTF through the web converter on your website.

  3. I wrote the 20 byte binary header, and append the bglTF after the header. The batchlength and batchtablelength are both 0.

  4. I add and modified three parts of the bglTF in .b3dm after appending:

I add CESIUM_RTC to extensionUsed:


And I add center ECEF coordinates to CESIUM_RTC, the coordinates are generated by Cesium.Transforms.eastNorthUpToFixedFrame from a origin in WGS84.

“extensions”: {


  "center": [







And I changed the modelViewMatrix to CESIUM_RTC_MODELVIEW:

“techniques”: {

"technique0": {

  "parameters": {

    "modelViewMatrix": {

      "semantic": "CESIUM_RTC_MODELVIEW",

      "type": 35676


  1. And I modified the byteLength field in the header to the right bytelength after all modification.

However, the models is not displayed when I load the tileset.json in 3d-tiles example in Sandcastle,

The camera manged to fly to the right location and the console exports like this:

[Color]: Visited: 0, Selected: 0, Commands: 0 | Requests: 0, Processing: 0, Ready: 0, Total: 1 | Tiles styled: 0, Features styled: 0

[Color]: Visited: 0, Selected: 0, Commands: 0 | Requests: 1, Processing: 0, Ready: 0, Total: 1 | Tiles styled: 0, Features styled: 0

[Color]: Visited: 1, Selected: 0, Commands: 0 | Requests: 1, Processing: 0, Ready: 0, Total: 1 | Tiles styled: 0, Features styled: 0

[Color]: Visited: 1, Selected: 0, Commands: 0 | Requests: 0, Processing: 0, Ready: 0, Total: 1 | Tiles styled: 0, Features styled: 0

But I can not see models and even boundingRectangles. I guess I miss some important parts but I can’t see it.

Any help appreciated.



在 2016年8月24日星期三 UTC+8下午11:22:03,Sean Lilley写道:

This is my tileset.json and .b3dm

parent.b3dm (7.29 KB)

tileset.json (556 Bytes)

I noticed a few problems. Your byteLength is 448,643,055 whereas the actual tile byte length is 7464. Also it looks like the glTF starts at byte 22 rather than byte 20.

Hello Sean
Thanks for your help again. Sorry for my little mistakes, I have modified the bytelength field and move the glTF at byte 20.

And I also find the CESIUM_RTC center is not within the boundingVolume, so I modified the center value.

But I still cannot see the models and boundingRectangle.

I should mention that all the boundingVolume region are typed manully. So I wonder if the boundingVolume of root tile should tightly surround the models? Or does it matter?

The following files are my tileset.json and the modified parent.b3dm



在 2016年8月26日星期五 UTC+8下午8:57:46,Sean Lilley写道:

tileset.json (556 Bytes)

parent.b3dm (7.29 KB)

I think the problem now is is you edited the glTF manually but didn’t update the contentLength field: https://github.com/KhronosGroup/glTF/tree/master/extensions/Khronos/KHR_binary_glTF. It may be easier if you use the online converter, uncheck the binary gltf checkbox, modify the gltf, then run through the converter again with the binary checkbox set.

I should also warn in advance that using the CESIUM_RTC extension will only translate the model, and won’t orient it to fit the surface. In general using the “transform” property in tileset.json is the easier way to go.

Thanks Sean, now I see the models in the right place. As you said, the models can’t be orientated rightly.
So I try to use the transform property. But I don’t how to define the boundingBox, so I copy the transform and boundingVolune in TilesetWithDiscreteLOD/tileset.json

I can see the models on the surface,but they are too big, and out of the boundingVolume like the picture below:

The red box is the boundingVolume and the model shouldn’t be that large.

在 2016年8月26日星期五 UTC+8下午11:36:50,Sean Lilley写道:

You won’t have much luck with using the same bounding box and transform on a different model. The transform in TilesetWithDiscreteLOD has a scale in it so that explains why they are so big. This is the code I used to make a bounding box and transform:

var centerLatitude = 0.698874;
var centerLongitude = -1.31968;

var dragonWidth = 14.191;
var dragonHeight = 10.075;
var dragonDepth = 6.281;
var dragonBox = [0.0, 0.0, 0.0, dragonWidth, 0.0, 0.0, 0.0, dragonDepth, 0.0, 0.0, 0.0, dragonHeight];
// this line above swaps from y-up to z-up, but there will be a change in Cesium soon for all local bounding volumes to stay y-up
var dragonScale = 100.0;
var dragonOffset = dragonHeight / 2.0 * dragonScale;
var dragonCartesian = Cartesian3.fromRadians(centerLongitude, centerLatitude, dragonOffset);
var scaleMatrix = Matrix4.fromUniformScale(dragonScale);
var wgs84Matrix = Transforms.headingPitchRollToFixedFrame(dragonCartesian, 0.0, 0.0, 0.0);
var dragonMatrix = Matrix4.multiply(wgs84Matrix, scaleMatrix, new Matrix4());
var dragonTransform = new Array(16);
Matrix4.pack(dragonMatrix, dragonTransform);

Thanks Sean, I finally figure out how to create .b3dm tiles. I have a few questions:

  1. If I use the transform matrix in root tile, can I use another transform matrix in children tile? (maybe the two models have different centers)

  2. When I use the code you offered to generate box matrix, the I will lift the models at the height of dragonHeight/2. I guess that’s because the origin of my glTF model is on the ground.

So I change the var dragonOffset = dragonHeight / 2.0 * dragonScale to var dragonOffset = 0. Then the models are on the ground, but the boundingVolume are buried half into the earth.

Then I change the Box to Region, and find out it also works well. I want to know is there a solution for this problem or should I change the origin when building the models?

  1. My .b3dm has no batchTable, so they are just models with no information. Are there any tutorial for add batchTable into .b3dm?

BTW, I learn so much from you this week and that make more insterested in 3d-tiles. I should say the whole community is great and hope you create more innovative techs.



在 2016年8月27日星期六 UTC+8下午11:24:30,Sean Lilley写道:

  1. Yes you can do that

  2. You will need to update the boundingVolume box as well. The first three values are the center position - you may want to change the 2nd value to half the height of the model.

  3. The glTF model will need a batchId vertex attribute. You may be able to examine our example tilesets and work backwards to see what’s going on in terms of the glTF, but as of now we don’t have any tutorials for doing this.

Thanks for your interest in 3D Tiles!

Quick edit: For number 2, you should edit the 3rd value, not the 2nd. However this will change in Cesium pretty soon.

Hi Sean, I’m now trying to figure out batch table. But I don’t know how to add batchID to the glTF.
I find there are places in glTF relating to batchID:

  1. “techniques”:{“technique0”:{“attributes”:{“a_batchId”:“batchId”,“a_normal”:“normal”,“a_position”:“position”},“parameters”:{“ambient”:{“type”:35666},“batchId”:{“semantic”:“BATCHID”,“type”:5126}…

  2. “primitives”:[{“attributes”:{“BATCHID”:“accessor_27”}…}…]

  3. “accessor_27”:{“bufferView”:“bufferView_30”,“byteOffset”:33600,“byteStride”:2,“componentType”:5123,“count”:2400,“max”:[99],“min”:[0],“type”:“SCALAR”}

Then I find the accessor_27 contains the batchID buffer. So I guess I need to fill the buffer in glTF with batchID.

So I open an ordinary glTF file and find the buffer containing position and normal data (should the batchID be put in the same buffer?).

The buffer is organized like this:

“buffer_0”: {

“type”: “arraybuffer”,

“byteLength”: 1512,

“uri”: “data:application/octet-stream;base64,//8AQzpej0…UABcA”


Now, I have a few questions:

  1. Is the uri containing the position and normal data?

  2. Should the batchID also be in the above uri?

  3. What does octet-stream mean? How can I read the encoded data? It seems this data has been encoded twice (base64 and something related to octet-stream).

  4. After I manage to add batchID into the buffer, and modify the abovementioned parts relating to batchID (including batchTable). Can I get the right .b3dm with batchTable and display it in Cesium?.



在 2016年8月30日星期二 UTC+8上午12:05:46,Sean Lilley写道:

Sorry, I find out the octet-stream means binary file.
I’d like to change Question 3 to: How can I append batchIDs to the base64 encoded uri data?

在 2016年8月30日星期二 UTC+8下午9:01:04,Chris Wang写道: