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;
}