Closed xeolabs closed 4 years ago
When loading an XKT from a file with
this.model = this.xktLoader.load({
xkt: file,
edges: false,
});
performanceModel.fire("loaded", true, true);
is never called
I have few issues with XKT v2 :/
Many elements are flattened : All fire hoses and many pipes are flat, as if they're in 2D.
Here is the conversion log:
npx @bimdata/gltf-to-xkt bugged.gltf bugged.xkt # Converting gltf to xtk is very simple!
npx: installed 4 in 1.022s
[INFO] Converting glTF bugged.gltf to xkt bugged.xkt
Number of objects: 12474
Only once meshes: 11856
More than once meshes: 618
Total mesh instances: 24925
Instancing factor 52.43%
arrayBuffer takes 6065.123 kB
When unsuccessfully trying to isolate the bug (I can't share the full GLTF), I found another:
GLTF:
XKT:
Here are the files: bug1.zip
I'm still trying to isolate the first bug
@Amoki I'm going to add a switch to xeokit-gltf-to-xkt so that we can make it convert to XKT V1, so we can isolate whether it's a XKT V2 specific bug.
The first bug (plat pipes) is XKTv2 only.
The second bug is both XKT 1 and 2
Just a question: could this be the case of nested GLTF nodes?
(I'm on the mobile now and can't open the GLTF file with a text editor.)
@Amoki, just downloaded your bug1.zip file and visualized the GLTF file with a GLTF model viewer installed from Google Play.
The pipe appers flat.
(Maybe I misunderstood the problem, but) could this be a problem with your GLTF generator?
On the bug1.zip GLTF, there are two fire hoses and two red marks that are flat. The bug is there are two of them in the GLTF and only one is shown on the XKT.
On the full model that I can't share, the GLTF is OK (so the generation doesn't seem to be a problem), but pipes are flat in the XKT.
Here are more screenshots: GLTF:
XKTv2:
Now I see.
On the deflateData
function of modelToXKT.js
, can you add the following line (as first line in the function)?
console.log (data.positionsDecodeMatrix);
And put here the generated output?
That comes from an idea from Lindsay about quantization problems.
Also, another request:
On the last line of the finalize
method of Model.js
, can you add:
console.log (aabb)
And put the output here?
If the idea from @xeolabs about the quantization problem is right, it's possible that you won't be able to reproduce the problem by using an isolated case with a simplified GLTF model.
If the idea is right, the problem comes from the fact that the bounding box the complete scene is large, and instanced meshes (meshes, not nodes) bounding boxes are small when compared to the complete scene bounding box.
This will be seen from the two requested console.log
statements.
The allowed accuracy is about scene_bbox/2^16
.
This means that if the bbox of the scene is 100m, you get an accuracy of 100/65536, which is about 1.5mm.
Just another comment (sorry this looks like a twitter thread 😜).
If the supposition is true, it simply means different position decode matrices
are needed for instanced meshes and for non-instanced meshes.
The problem is as follows, when it comes to calculate the global bounding box:
for non-instanced meshes, the positioning matrix is applied to the geometry before calculating the bounding box
for instanced meshes, as each mesh instance has its own positioning matrix applied at runtime, the matrix is not applied yet at XKTv2 generation time. The bounding box is calculated using local mesh coordinates (without world placement)
Let's put the example that scene X extent is 100m, but the left side of the bouding box is at X coordinate +10000. And there is some instanced mesh defined in local coordinates centered at X = 0.
Then, due to the mixed way of calculating bounding boxes, the generation time scene bounding box
has a bounding box with X size = 10000.
And then the accuracy is not anymore 100/2^16=1.5mm (as it would be expected from the scene bbox), but 10000/2^16=15cm (due to perceived bounding box caused by the encoding mechanism).
Still suppositon, but if that is true, a simple way to have all meshes encoded in absolute world coordinates (and thus precenting that bounding box expansion (that leads to decreaded accuracy)), would be, for each instanced mesh, apply the placement matrix of the first node that uses the mesh, and for further nodes using the same mesh, calculate a composite matrix M1*M2
, where M1
undoes the placement done by the first-using node, and M2
are further nodes' placement matrices.
That would be a very simple way of solving this concrete problem 😊 : would keep the encoding process very simple, and would prevent adding additional position decode matrices
in the binary file. After all, if some geometry is instanced and some not, the accuracy would be still limited by the REAL scene bbox, not the expanded one.
What do you think, @xeolabs?
Convert output:
AABB Float32Array [
-11.51853084564209,
-157.57345581054688,
-2.8572535514831543,
253.8859405517578,
21.95928955078125,
29637.595703125 ]
Number of objects: 12474
Only once meshes: 11856
More than once meshes: 618
Total mesh instances: 24925
Instancing factor 52.43%
positionsDecodeMatrix Float32Array [
0.004050430841743946,
0,
0,
0,
0,
0.0027399121318012476,
0,
0,
0,
0,
0.4523533582687378,
0,
-11.51853084564209,
-157.57345581054688,
-2.8572535514831543,
1 ]
arrayBuffer takes 6065.123 kB
The model is about 250m long.
yes, we couldn't reproduce the bug with a subset of the model...
Ok:
On the bug1.zip GLTF, there are two fire hoses and two red marks that are flat. The bug is there are two of them in the GLTF and only one is shown on the XKT.
There is indeed a bug in XKTLoaderPlugin.js
bug that prevents loading the last entity (sic!).
The following line of code...
... should be replaced with:
for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshIds.length : entityMeshes [i + 1]; j < jlen; j++) {
That's it!
Convert output:
-11.51853084564209, -157.57345581054688, -2.8572535514831543, => z_min 253.8859405517578, 21.95928955078125, *29637.595703125 => z_max ]
The Z extent of the bbox (z_max - z_min) is 29.640 km.
This gives us an accuracy of 29640 m / 2^16 = 45cm, and for this reason the objects appear flattened.
Lets try that idea of positions decode matrices :), will come back here later.
Indeed, those factors in the positionsDecodeMatrix are the accuracy in model units (meters in our use cases):
positionsDecodeMatrix Float32Array [ 0.004050430841743946, => X_accuracy 0, 0, 0, 0, 0.0027399121318012476, => Y_accuracy 0, 0, 0, 0, 0.4523533582687378, => Z_accuracy 0, -11.51853084564209, -157.57345581054688, -2.8572535514831543, 1 ]
Ok, for the flattening bug, can you try to replace in the following file...
https://github.com/xeokit/xeokit-gltf-to-xkt/blob/xkt-v2/src/lib/glTFToModel.js
... the following code...
if (meshOnlyUsedOnce) {
meshMatrix = matrix ? matrix.slice() : math.identityMat4();
entityMatrix = math.identityMat4();
} else {
meshMatrix = math.identityMat4();
entityMatrix = matrix ? matrix.slice() : math.identityMat4();
}
... with the following one?
if (meshOnlyUsedOnce) {
meshMatrix = matrix ? matrix.slice() : math.identityMat4();
entityMatrix = math.identityMat4();
} else {
if (meshInfo._firstMatrixInverse === undefined) {
meshInfo._firstMatrixInverse = math.inverseMat4 (
matrix ? matrix.slice() : math.identityMat4()
);
meshMatrix = matrix ? matrix.slice() : math.identityMat4();
entityMatrix = math.identityMat4();
} else {
meshMatrix = math.identityMat4();
entityMatrix = math.mulMat4 (
matrix ? matrix.slice() : math.identityMat4(),
meshInfo._firstMatrixInverse,
math.identityMat4 ()
);
}
}
And see it that solves the flattening problem?
It works! :tada: :champagne:
The size increases from 6065.123 kB to 7680.298 kB but it's still awesome compared to the 60MB of the GLTF.
Do you want me to submit the PRs?
Do you want me to submit the PRs?
👍
The size increases from 6065.123 kB to 7680.298 kB
The size increase is due to the fact that the "lost information" due to wrong quantization was "recovered" 😉
Do you want me to submit the PRs?
Go for it!
PS: The idea that this was a quantization problem came from @xeolabs.
Upgrade the XKT format to support geometry reuse.