Hi all, I have some questions about the RTC_CENTER
property
that may be optionally included in .b3dm files and similar.
My understanding of RTC_CENTER
If I understand correctly, RTC_CENTER
is supposed to be a high-precision
model-space-to-worldspace transform (aka modeling matrix), that the viewer
program should multiply by a high-precision worldspace-to-eyespace
transform (aka view matrix) in high precision on the CPU,
so that matching large translations can cancel out in high precision
and the product modelspace-to-eyespace transform (aka modelview matrix)
can be safely rounded to single precision and used on the GPU.
Given that, I expect RTC_CENTER
to be expressed and used
as double-precision floating point numbers (aka doubles, aka float64’s).
The tileset expresses it as simply numbers in JSON
(in the feature table in the .b3dm file or similar), so no problem there.
Conflicting indicators in the docs
However, there seem to be conflicting indicators in the 3D Tiles documentation.
For example, the following docs say that RTC_CENTER
is of type float32[3]
, which is surprising to me:
- 3d tiles overview pdf, sections 10.2, 10.3, 10.4
- 3d tiles spec->Batched 3D Model->Semantics
But, in this other place in the same spec, it says it’s
a number[3]
or GlobalPropertyCartesian3
object, instead,
i.e. effectively float64[3]
, which would make more sense to me:
So, which is it?
If it’s indeed float32[3]
, what does that mean?
Does it mean the viewer program is supposed to
read the numbers from the JSON and round them to the nearest float32
's?
Taking this example from the pointcloud part of the spec:
var featureTableJSON = {
...
RTC_CENTER : [1215013.8, -4736316.7, 4081608.4],
...
};
When rounded to nearest float32
s, those numbers are exactly:
1215013.75, -4736316.5, 4081608.5
(if I did the math right).
So such rounding would move this point by more than 0.2 meters, so whether it’s
done or not certainly matters.
Conflicting indicators in the cesium source code
To try to see what the cesiumjs viewer does,
I searched for “RTC_CENTER” in the cesium source code,
and I found 4 occurrences. In at least one of those places,
(that is, Source/Scene/Geometry3DTileContent.js)
it looks to me like it’s using the values directly out of the JSON
without rounding to float32
s, and putting them directly into the modeling
matrix in high precision:
var center;
if (defined(featureTableJson.RTC_CENTER)) {
center = Cartesian3.unpack(featureTableJson.RTC_CENTER);
Matrix4.multiplyByPoint(modelMatrix, center, center);
}
... (and then doing more stuff with center down below) ...
But in the other 3 places in the cesium source code, it looks like it’s
converting to float32
s. For example, in Source/Scene/Batched3DModel3DTileContent.js, there is this:
var rtcCenter = featureTable.getGlobalProperty(
"RTC_CENTER",
ComponentDatatype.FLOAT,
3
);
if (defined(rtcCenter)) {
content._rtcCenterTransform = Matrix4.fromTranslation(
Cartesian3.fromArray(rtcCenter)
);
}
(Note that ComponentDatatype.FLOAT means float32.)
Safe strategy for tileset creator?
As a tileset creator, I’m taking a strategy that seems safe,
regardless of what various consuming code might do with it:
- I always choose an
RTC_CENTER
that is exactly representable infloat32
, and - When expressing that
RTC_CENTER
in JSON, I always print it
with enough digits so it will come out exactly for all consumers,
regardless of whether they round to float or not.
(That is: print the numbers exactly, or at least enough digits to
unambiguously represent double precision, i.e.%.17g
;
%.9g
does not suffice, although it would suffice
if I knew all consumers rounded and stored the values asfloat32
).
E.g. I would have to rewrite the example above as:
if that’s the value I chose.RTC_CENTER : [1215013.75, -4736316.5, 4081608.5],
Summary of questions
So my questions are:
- Is my characterization of the situation correct?
- Do any of the references to which I’ve linked above point out bugs
in the spec or viewer programs, that need to be fixed? - Is my “safe” strategy as a tileset creator a good one?