The reason why I’m trying to compute the geometric error this way is because that’s the only way that comes to my mind, as this is my first time doing game development itself, rather than just mods or models for games. If there’s another way to find it, I would gladly appreciate the advice.
Regarding the code itself, here are the two most relevant methods. The first one navigates through the tileset tree/populates it (parsed tiles from the API are stored in a local database), while the second one checks if the origin point is within the OBB of the 3D Tile. Note, for FindMeshTile
method parameters, tile
is the starting tile, ergo the Global Root Tile (when FindMeshTile
is called the first time), meshTileID
is a composite primary key ( made from the tile UUID, dataset index, and tile type), meshTileUrl
contains the data to construct the URL of the tile (the key, session, name (UUID), dataset name, tile type (.json or .glb)), geoCoords
contains the properties from CesiumGlobeAnchor.longitudeLatitudeHeight
, origin
is the calculated cartesian double vector from said geoCoords
, and lastly meshTransform
is the calculated beforehand (before FindMeshTile
is called) transform matrix from the Global Root Tile.
public static Model.Tile FindMeshTile(Tile tile, string meshTileID, ParsedUrl meshTileUrl, Vector<double> origin, GeoCoords geoCoords, ref Matrix<double> meshTransform) {
if (tile.ID == meshTileID) {
return tile;
}
//If tile is type of JSON, and It's not processed yet (It's TileSet not yet in the database)
if(tile.GetTileType() == TileType.JSON && !tile.Processed) {
tile = RequestTileset(tile, meshTileUrl.Key, meshTileUrl.Session);
Tile tile1 = sceneDatabase.GetTile(meshTileID);
if(tile1 != null) {
meshTransform *= VectorUtility.MatrixFromArray(tile1.GetTransform());
return tile1;
}
}
//Check if requested tile is inside of the child tiles of the tile
List<Tile> childTiles = sceneDatabase.GetChildTilesFromParentTile(tile.ID);
List<int> overlappingTilesIndexes = new List<int>();
for (int x = 0; x < childTiles.Count; x++) {
Tile childTile = childTiles[x];
Matrix<double> childTransform = meshTransform * VectorUtility.MatrixFromArray(childTile.GetTransform());
//Check if Cartesian origin point is inside the BBO
if (childTile.GetVolumeType() == BoundingVolume.VolumeType.BOX && VectorUtility.IsPointInsideOBB(origin, childTile.GetBounds(), childTransform))
overlappingTilesIndexes.Add(x);
else if (childTile.GetVolumeType() == BoundingVolume.VolumeType.SPHERE && VectorUtility.IsPointInsideBoundingSphere(origin, childTile.GetBounds(), childTransform))
overlappingTilesIndexes.Add(x);
else if (childTile.GetVolumeType() == BoundingVolume.VolumeType.REGION && GeoUtility.IsGeoCoordInsideBoundingRegion(geoCoords, childTile.GetBounds()))
overlappingTilesIndexes.Add(x);
}
foreach(int overlapingIndex in overlappingTilesIndexes) {
Tile childTile = childTiles[overlapingIndex];
Matrix<double> childTransform = meshTransform * VectorUtility.MatrixFromArray(childTile.GetTransform());
Tile tile1 = FindMeshTile(childTile, meshTileID, meshTileUrl, origin, geoCoords, ref childTransform);
if(tile1 != null) {
meshTransform *= VectorUtility.MatrixFromArray(tile1.GetTransform());
return tile1;
}
}
return null;
}
public static bool IsPointInsideOBB(Vector<double> point, double[] bbo, Matrix<double> transform) {
//Get volume bounds of child tile
//Center of the BBO
Vector<double> center = Vector3(bbo[0], bbo[1], bbo[2]);
//X axis direction and half length of BBO
Vector<double> xAxis = Vector3(bbo[3], bbo[4], bbo[5]);
//Y axis direction and half length of BBO
Vector<double> yAxis = Vector3(bbo[6], bbo[7], bbo[8]);
//Z axis direction and half length of BBO
Vector<double> zAxis = Vector3(bbo[9], bbo[10], bbo[11]);
//Transform BBO by transform matrix
center = transform.MultiplyPoint3x4(center);
xAxis = transform.MultiplyVector(xAxis);
yAxis = transform.MultiplyVector(yAxis);
zAxis = transform.MultiplyVector(zAxis);
//Vector from the center of the OBB to the point
Vector<double> dir = point - center;
//Project dir onto each of the OBB local axis
double X = dir.DotProduct(xAxis.Normalize(2));
double Y = dir.DotProduct(yAxis.Normalize(2));
double Z = dir.DotProduct(zAxis.Normalize(2));
double xMagnitude = xAxis.L2Norm();
double yMagnitude = yAxis.L2Norm();
double zMagnitude = zAxis.L2Norm();
bool insideX = Math.Abs(X) <= xMagnitude;
bool insideY = Math.Abs(Y) <= yMagnitude;
bool insideZ = Math.Abs(Z) <= zMagnitude;
//Check if the point lies inside the extent of the OBB foreach axis
return insideX && insideY && insideZ;
}