cesium
cesium copied to clipboard
Precision of position attribute in Point Cloud is good on Y axis, but bad on X and Z axis
What happened?
I want to color the points of a point cloud based on their distance to a certain position. You can also have a look at this community forum post to see how this position is calculated.
I expected a nice gradient, from yellow to red, but instead got those "patches":
I used a Point Cloud Style for that.
I also wanted to color the points of a point cloud based on their distance to the ground. I used a custom shader for that.
I expected a nice rainbow gradient, however, I got "patches" again:
To me, it seems to be a precision issue. Interestingly, this issue only happens in x direction and z direction:
However, the y direction yields a nice gradient (especially noticeable at the smaller tower to the right) :
I expect the precision of the x and z direction be as high as the y direction.
Reproduction steps
- Open provided Sandcastle.
- Change line 57 to
float distance = abs(point.x - positionAbsolute.x);
,float distance = abs(point.y - positionAbsolute.y);
orfloat distance = abs(point.z - positionAbsolute.z);
to see the precision differences in axis directions in the rainbow gradient. - Uncomment Line 88 and comment line 87 to see the example with the yellow-red gradient, this time defined by a point cloud style, instead of the custom shader.
Sandcastle example
https://sandcastle.cesium.com/#c=pRdrU9s48K9omM7UuTOKHTsPKO0cl6YlAxSGBPolM8GxlUR3spST5YTQ4b/fSrKdF+1wc/mAtat9v7TU67eCcoW6TOQJmqzRrRRTjG6JIhKdM0a4i7qC5emERuie0yWRGVVrdCcmQtE4Q1fRBKNBHHFO+UwLOGfkr4gnUqChFHEsGEUAoutIEYq6VMSRZJTgEY8FzxRaUrICVR8RJyvUJRnNU/xgcM7oKDZwV3AVUU7k6MhFP0YcITBOAua0ZBhaGE+lSL8LyZIC4dTcEX+pfRjxEV9GEs3BEravbRBLQvhgEcWktyRcXVgix1qGs5hwgsHBZZRpSYUMnBHV54tcnceKCu5Mc24PRMuoWTsR0lrBYwWqIg56d4QuaPz3rYB4Vnx4UYBak+bXQRKMYCZmTiVHX764P7N/uF4QfNX7Mhx3r/rdS+s9+L/rTkpkpH3QsXaMsQnJFOWR1n66HZ9uqTZwrE1h6PntMMStMPTDZuCHrsU3Gk2v6ePQ99qdE9/3mo3iImyeNMOGh4N22O6EYRBodM1cCknB5EOlFyRKoKBuqYrnd4KxQnUTlLbaQdDxml5w0m62Cw3HHm60Wy2v7TeDTnDS6bSKixZudHywpdNuhp7ndZql6q2qyNSaEchNkbKETKHYMnRaIgySZiriMQHse6cEnHc/bm8G/WH/5tv4/M/BzdX9sAd5WZI4cEyQvBC3PTCs0+kErokPYBqtk7bfALOaLdeGJgCylt/wANOo1WqojhrvreoXtywDJqTWndInxwDQHWvCmFiNjmouKlGSJAZ+96O08aX2vpCx0I0+oM8ExDQ08qWKwFRGsxTyMJhHCZFD8qQgHI9wJ2hSXV7rhvpSAKb00TQzXxdRLgCMn9NxKhLCdLNLGjGUFofaiEMwR6qEcUKn0zzTUdceLcdg7oJFa8M+1gmB5I+NVy7aZ3KRh33TAyP+WPkAk0mRp30P7JCZMhEp9PXu/HO/9204vuj1v14MgaCBvbI7IGdoni0bcjZxDBCbHh4pAEJ0qVsXDo6PPVezQY4CffQ3R/hjakoZ9gVwRJPMgejFyonx09MT+h1d4qf1cw39BnXpoWMAV6uVZZJE5ZKjGD/DrY7JpWaBzLIoXTgLQ2wQXqFWZx2vizAUqbIxMIl6MEebpuVP0mRpbnJlieyhGF3WCfM2fPyfFW1CXEm08+26q8Vau3CklKSTHKYM3tx/OOA5n8AoBKrSoMoPiJhJzobZRqjUbNNftbBNjPENon18IB8/7zLOc83jgKqq8939YjJdu4fbeABFBRK2y0sXEqgG0cbUjb3A8YtmACkgoahZVOUMV71dFXXVG7YD4jxTIrXdsfv8dbdunGLiMTqbw1swu9bRrV7Zq20svv921R8WoyXndCpkmu2MzHy8mmWd8IaTG6jLO5jndPBPHsGI2iHTPwVPVqXm3gozz9hDrxu4u7TLiOUb4h5jdJFB7ePvXwedEItDbVv85TgtvzA31uDQrt31OhrYmBdjV82hCGgG7ziLcwbDKIFGKnoNZTakesWJFgvYbMxlOTOL643wXyW3curBmrUfgcrqvUl3eoApCA/H+ukruM1jOOJKrm0obNUoygjsCLpjVhFVVcmYT/B5aK/N2tWH/sn0TpQ4fits+LaWCwF4r/y2wQ864GfH//FXBDtDEdKL3kSs0ExC0sEzrRdElqrL13275Lfs16kmjiGqvdmULe32EbYdg1ZUzSH7+hXW3bmz60mawpRZwoyLksQprDPjGwoLthzkwM4qZG0T/3Lve+zpCwSzSK9EpWOn8MgbjpdHK+VNS96b1rzDBe+13e5wrasVdffmpe5wnXttkztc4mpFyR65R2cmdZ/KDvuDpgshFcolczCuK5IudMdm9Uke/60LMcvK1fqsvs16ltAlosnHV/7p0G9wlsHNNGdMD9nR0aezOtAfsBYp0hMIWlyTzf1PVxaJMT6rA/g6pxKCTSK5J/lf
Environment
Browser: Firefox, Chrome CesiumJS Version: 1.113 locally, and the current one in the sandcastle is 1.114 Operating System: Windows
Just a note: We had a look and found out, that the Y coordinate is simply 10 times smaller than the X and Z values. That's just because of the ECEF coordinate system. So at other places the X or Z precision might be much better than the Y one. This means the precision problem is not better or worse for any "direction" (x, y, z). It's just about the size of the respective coordinate value.
So the question is not, why X/Z values have worse precision, but how could we achieve better precision in general?
Is it possible to somehow get better precision in the shader based on something like RTC_CENTER
, like Cesium does when actually placing the points in the 3D scene?
The relevant shader lines are:
vec3 point = vec3(4401704.702768883, 225004.26971228156, 4595434.761201562);
vec3 positionMC = vsInput.attributes.positionMC;
vec3 positionAbsolute = vec3(czm_model * vec4(positionMC, 1.0));
float distance = abs(point.z - positionAbsolute.z);
The problem is that point
and positionAbsolute
are both in world coordinates. So the distance calculation is subtracting two numbers that are very large, and very similar. This results in precision loss due to subtractive cancellation.
You can avoid it by defining the reference point in model coordinates, and compare to positionMC
. In this way the distance calculation will be subtracting smaller numbers with a larger relative difference between them.
vec3 referencePointMC = vec3(0.0, 0.0, 50.0);
vec3 positionMC = vsInput.attributes.positionMC;
float distance = abs(referencePointMC.z - positionMC.z);
See this updated Sandcastle demonstrating the model coordinates approach in the custom shader.
Thanks @jjhembd for your idea. Unfortunately, this does not work, since the values might be different per tile. I guess this is because the model matrix should be different?
It becomes more apparent if you set HEIGHT_GRADIENT
to 20.0
in your updated sandcastle and move around to trigger loading tiles, you might find views like this:
Hi @anne-gropler @jjhembd , is there any progress on this issue?
In this post, I also face similar precision loss issues:
I want to convert the model coordinates to world coordinates in CustomShader
, complete some operations in the world coordinate system, and then convert the world coordinates to model coordinates, but I lost precision during this process.
const modelShader = new Cesium.CustomShader({
vertexShaderText: `
void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput)
{
vec4 positionWC = czm_model * vec4(vsInput.attributes.positionMC, 1.0);
vsOutput.positionMC = (czm_inverseModel * positionWC).xyz;
}
`,
});
Hello @syzdev , no, we still have the same problems and we don't know how to solve them.