I want to place a tileset at the current position of the camera. However, I am encountering an issue where far away tilesets have an incorrect rotation. They should be aligned perpendicular to the surface, meaning they should “lie flat on the surface.”
What is the easiest way to achieve this?
The following example illustrates my problem. Using the “Place” button, the tileset is moved to the camera position:
I think you’ll need to adjust the orientation to align with the curvature of the earth. There’s an example of creating a modelMatrix from Transforms.headingPitchRollToFixedFrame in this Sandcastle example.
The way how this functionality may be implemented depends on some details of the tileset that you can not know beforehand in general, and that may sometimes be hard to determine even for one specific case. The main point is: How is the placement of the tileset done initially? There are different possibilities for that. Roughly speaking: The placement could be stored in the geometry data (unlikely, but not impossible). Or it could be stored in the root.transform of the tileset. Or it could be stored in other tile transforms. Or it could be accomplished with the modelMatrix.
In the tileset that you used as an example here, the transform is stored in the root.transform. So you have to “remove” this transform, by setting it to IDENTITY. Afterwards, you can compute the desired transform, using Transforms.eastNorthUpToFixedFrame for the desired target position, and assign this as the modelMatrix of the tileset:
Ahh, okay thanks. I already suspected that there wouldn’t be a simple and universal solution for this. One idea I had—but I’m not sure how to implement it—would be to determine the UP vector of the surface at the initial position and the UP vector at the target position, then use these to calculate the rotation. This assumes that the tileset is correctly rotated at the initial position. In that case, it shouldn’t matter how the initial rotation was set up, since the tileset would only receive an offset rotation.
However, in my example, the tileset is always in space:
The sandcastle does not seem to contain the line tileset.root.transform = Cesium.Matrix4.clone(Cesium.Matrix4.IDENTITY);
which is pretty important here. Adding this line (immediately after the tileset was created) makes it appear at … roughly the right height (not perfect, but close).
I didn’t go through the math in your sandcastle. But there are many details to consider when trying to place a tileset. The root.transform mentioned above is only one of them. But another one is that you are using the bounding sphere center as the reference point. Imagine that tileset (the building that you are adding there) contained one reeeeally tall tower (like some radio tower, 500 meters high). Then the bounding sphere center would be at a height of ~250 meters. Using that as a reference would place the tileset ~250 meters below the ground.
The question about “placing tilesets” (or more generally: “placing data in a geospatial context”) comes up pretty frequently…
Thank you very much! My idea with the UP vectors at the initial and target positions was also partially generated with AI, and they don’t have the best understanding of Cesium. I just assumed that with this approach, the initial rotation shouldn’t matter—whether root.transform is set or not. However, I don’t know enough about the internal rotation calculations of tilesets and their respective components to find a solution.
Alternatively, wouldn’t it be possible (after loading) to reset all rotations and transformations of a tileset to zero or its initial state and then position it using Transforms.eastNorthUpToFixedFrame?
Again, there are several things coming together, and many possible corner cases. You could have a tileset that is canonically located at (0,0,0), i.e. the center of the earth, and where the root.transform is the identity matrix(!), but where the root tile contains two children that both have a transform, and … one of the children could contain geometry that is placed at the north pole, and the other child could place its geometry at the south pole One could say that this is unlikely, but there are very few constraints that prevent that, and certainly some more realisitic cases where similar questions come up.
However, the orientation of the tileset in the last Sandcastle that you posted was correct, wasn’t it? (It was just “placed in space”, due to the translation of the root tile). However, even when you align “two up-vectors” (say the original one and the desired one), then there are still infinitely many possible orientations for the result - namely, all rotations around the axis that is defined by that aligned vector.
You could make it more strict, and try to align the eastNorthUpToFixedFrame coordinate system at the old and the new position. That shouldn’t be too difficult (but I might also come up with corner cases where it raises additional quesitons …)
Honestly, in your example, I only see a line, but I think I understand the issue. The problem might be related to the fact that you’re using a globe with a heightmap terrain:
js
КопироватьРедактировать
terrain: Cesium.Terrain.fromWorldTerrain(),
From what I’ve read in the documentation, Cesium primarily operates with two terrain models:
Ellipsoid – A simplified model of the Earth, similar to a school globe, without elevation data. The average radius is about 6,400 km from the center.
Heightmap Terrain – A more precise representation of the Earth’s surface. Cesium uses the WGS84 standard, which has an accuracy of up to 10 cm (without adjustments for seismic activity, etc., post-1984).
It looks like your terrain dataset might contain positional errors relative to the reference point (judging by your description). I’ve worked with different datasets in Cesium for over four years, from the North Pole to the South Pole, and whenever issues arose, they were usually in the source file or from the data provider. Cesium’s GIS system itself is quite robust (except at very high altitudes, where imagery quality is poor, but the math remains accurate).