Open bbbbx opened 1 year ago
Model bounding sphere:
root node scale: 0.1 | root node scale: 1.0 |
---|---|
Thanks for the report @bbbbx!
I have encountered a similar behavior with i3dm
tiles, incorrectly clipping and warping vertices (looks like floatingpoint precision)
I can provide the tileset with some trees placed: Symbole_Baum_test_tileset.zip
The same tileset is working just fine in 1.83
.
i retried with a simpler example, cube 10 units.
The difference to the sandcastle InstancedOrientation
tileset is the extra attribute SCALE_NON_UNIFORM
this leads to wobbly vertex displacements :
I've found a workaround for cases when rtc_center
property is defined in i3dm files.
If rtc_center
is defined, the step for manual computation of a BoundingSphere and storing positions relative to the center is skipped. But if rtc_center
is equal to [0,0,0]
or Cartesian3.ZERO
, the manual computation should be used as well. This seems to correct the rendering for the provided cases.
Also reported in https://github.com/CesiumGS/cesium/issues/11617.
After this came up several times in the forum, most recently at https://community.cesium.com/t/disappearing-i3dms-on-map-navigation-again/34035 , I did a short debugging pass. Well. Not so short, actually. What's particularly humbling is that the statement that was made in the first comment, namely
the calculation of the bounding sphere of the model(scene graph/primitive/draw command) is wrong,
was spot on (and it took me a while to arrive at the same "insight").
Some details:
ModelSceneGraph.buildDrawCommands
function, it is creating the PrimitiveRenderResources
. The bounding sphere is computed from the min/max of the respective primitive, plus the 'instancing translation'. So far that sounds about right (with a caveat)DrawCommand
, it is taking the previously computed bounding sphere, and transforming it with the model matrix, which includes the transform of the glTF nodeThe caveat is that this node transform may, for example, involve scaling, and that scaling will therefore be indirectly applied to the instancing transforms when it comes to determining their effect on the bounding sphere.
Maybe it becomes clearer with some random debug log from some test model:
The case where it's not working, when a primitive is attached to a node with a uniform scale of 0.01:
primitive min/max is (-3558.85693359375, -2171.158447265625, -44.34097671508789) (3385.92578125, 3999.103271484375, 462.9575500488281)
instancing min/max is (-81.875, -975.484375, -156) (81.875, 975.484375, 156)
new primitive min/max is (-3640.73193359375, -3146.642822265625, -200.3409767150879) (3467.80078125, 4974.587646484375, 618.9575500488281)
Draw command bounding sphere is
center: Cartesian3 ...
radius: 54.11951398537193
This cannot be right. The instancing translations alone would require a radius of ~1000.
The case where it is working, because the scale of 0.01 is "baked" into the primitive, and the node transform is the identity:
primitive min/max is (-3.376162052154541, -1.1918214559555054, -13.400678634643555) (3.376161575317383, 103.71656036376953, 4.557344913482666)
instancing min/max is (-81.875, -975.484375, -156) (81.875, 975.484375, 156)
new primitive min/max is (-85.25116205215454, -976.6761964559555, -169.40067863464355) (85.25116157531738, 1079.2009353637695, 160.55734491348267)
Draw command bounding sphere is
center: Cartesian3 ...
radius: 1044.5781589720143
The bounding sphere here is properly computed from the primitive min/max plus the instancing min/max. No scaling is applied afterwards.
Now, the question is still: How to solve this?
One could be tempted to just omit some scaling here or there, to compute the proper bounding sphere.
But it's not that simple.
There could be instancing information (like from EXT_mesh_gpu_instancing
) that actually is attached to a node that involves a scaling. And in this case, the instancing translations should be affected by the node transform.
In contrast to that, the I3dmLoader.createInstances
function assigns the instancing information that was created from the I3DM data to all nodes of the glTF, regardless of whether they contain a scaling factor or not. This means that the instancing translations should not be affected by the node transform.
(I'm talking about "affecting" here - I should be more precise, and say whether this affects the rendering or some bounding volume computation in some draw command. But .. it's complicated. One thing that I want to try out is whether the rendering even works properly when there is an I3DM for a glTF that contains two nodes with different scaling factors. It's not yet clear whether the "error" here is really only affecting the draw command bounding volume part, or whether it also affects the rendered instances. I hope that it's only the draw command. But this has to be investigated further)
@bertt already provided very helpful data in the forum thread...s, that helped to narrow down the issue.
I created another test ("CC0", so to speak).
It is an I3DM with positions
new float[] {
0.0f, 0.0f, 0.0f,
10.0f, 0.0f, 0.0f,
0.0f, 10.0f, 0.0f,
10.0f, 10.0f, 0.0f,
}
This is used to create four instances of a GLB that contains some data that aims at
For the latter, there are a bazillion possible reasons. (I mean, starting with the fact that the I3DM only contains positions, but no scaling/up-vectors etc). But the glTF consists of 4 unit cubes:
(I obviously ~"tried to cover several cases" here. Doing this thoroughly and systematically, sneaking in scaling and translation (and maybe rotation etc) everywhere, and/or using transforms that "cancel out" each other, would yield a combinatorial explosion. The cases have been selected based on the insights from the debugging pass, just to have a few "hot candidates", and a first, basic test...)
The good news is: The bug does not affect the rendering of the instances themself. Regardless of the scaling and whatnot, they are all unit cubes at the proper locations:
The ... also good... ? or bad...? ... the other news is that this already shows the problem:
Only the green cube seems to ever disappear. It is the only one that is attached to a node with a global scaling less than 1.0. Based on the previous debugging pass, this is not toooo surprising: For the other cubes, it will just overestimate the size of the object, roughly meaning ~"a reduced culling-efficiency" - it will still 'render' these nodes even if it wouldn't have to.
I'll have a short look at possible solutions for all this, and maybe create a draft PR.
EDIT: Nearly forgot: Here's the test data, with a tileset JSON and sandcastle:
An old thread that very likely refers to the same issue: https://community.cesium.com/t/the-gpu-instantiated-artifacts-will-disappear-when-i-rotate-the-model-in-cesium/24688
When the transformation matrix of the glTF node of i3dm is not the identity matrix, the calculation of the bounding sphere of the model(scene graph/primitive/draw command) is wrong, causing the far and near planes of the viewing cone to be smaller than expected, and finally the pixels outside the bounding sphere are discarded in the fragment shader(writeLogDepth.glsl).
Screenshot:
https://user-images.githubusercontent.com/22176164/226557527-dbdad565-b8fc-4ee7-8f43-d4ead14cfa95.mp4
Sandcastle example: url
Browser: Google Chrome 111.0.5563.65
Operating System: Windows 10