int GetTileZoomLevel() { // Get screen dimensions of central tile int zoomLevel0 = 1; int zoomLevel1 = TILE_MAX_ZOOM_LEVEL; int zoomLevel = TILE_MIN_ZOOM_LEVEL; Vector2 latLon = Conversion.GetLatLonFromSpherePoint(GetCurrentMapLocation()); int xTile, yTile; currentTileSize = _tileSize > TILE_MIN_SIZE ? _tileSize : TILE_MIN_SIZE; currentTileSize *= (3.0f - _tileResolutionFactor); float dist = 0; for (int i = 0; i < 5; i++) { zoomLevel = (zoomLevel0 + zoomLevel1) / 2; Conversion.GetTileFromLatLon(zoomLevel, latLon.x, latLon.y, out xTile, out yTile); Vector2 latLonTL = Conversion.GetLatLonFromTile(xTile, yTile, zoomLevel); Vector2 latLonBR = Conversion.GetLatLonFromTile(xTile + 0.99f, yTile + 0.99f, zoomLevel); Vector3 spherePointTL = Conversion.GetSpherePointFromLatLon(latLonTL); Vector3 spherePointBR = Conversion.GetSpherePointFromLatLon(latLonBR); Vector3 wposTL = currentCamera.WorldToScreenPoint(transform.TransformPoint(spherePointTL)); Vector3 wposBR = currentCamera.WorldToScreenPoint(transform.TransformPoint(spherePointBR)); dist = Mathf.Max(Mathf.Abs(wposBR.x - wposTL.x), Mathf.Abs(wposTL.y - wposBR.y)); if (dist > currentTileSize) { zoomLevel0 = zoomLevel; } else { zoomLevel1 = zoomLevel; } } if (dist > currentTileSize) { zoomLevel++; } zoomLevel = Mathf.Clamp(zoomLevel, TILE_MIN_ZOOM_LEVEL, TILE_MAX_ZOOM_LEVEL); return(zoomLevel); }
void CreateTile(TileInfo ti) { Vector2 latLonTL = ti.latlons [0]; Vector2 latLonBR; ZoomLevelInfo zi = zoomLevelsInfo [ti.zoomLevel]; int tileCode = GetTileHashCode(ti.x + 1, ti.y + 1, ti.zoomLevel); TileInfo cachedTile; if (cachedTiles.TryGetValue(tileCode, out cachedTile)) { latLonBR = cachedTile.latlons [0]; } else { latLonBR = Conversion.GetLatLonFromTile(ti.x + 1, ti.y + 1, ti.zoomLevel); } // Avoid seams on very close distance to surface if (ti.zoomLevel >= 16) { float tao = 0.000002f * (ti.zoomLevel - 15); latLonTL.x += tao; latLonTL.y -= tao; latLonBR.x -= tao; latLonBR.y += tao; } // Create container GameObject parentObj; if (ti.parent == null) { parentObj = zi.tilesContainer; if (parentObj == null) { parentObj = new GameObject("Tiles" + ti.zoomLevel); parentObj.transform.SetParent(tilesRoot, false); zi.tilesContainer = parentObj; } } else { parentObj = ti.parent.gameObject; } // Prepare mesh vertices Vector3[] tileCorners = new Vector3[4]; tileCorners [0] = Conversion.GetSpherePointFromLatLon(latLonTL); tileCorners [1] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonTL.x, latLonBR.y)); tileCorners [2] = Conversion.GetSpherePointFromLatLon(latLonBR); tileCorners [3] = Conversion.GetSpherePointFromLatLon(new Vector2(latLonBR.x, latLonTL.y)); // Setup tile materials TileInfo parent = ti.parent != null ? ti.parent : ti; if (parent.normalMat == null) { parent.normalMat = Instantiate(tileMatRef); parent.normalMat.hideFlags = HideFlags.DontSave; } if (parent.transMat == null) { parent.transMat = Instantiate(tileMatTransRef); parent.transMat.hideFlags = HideFlags.DontSave; } Material tileMat = ti.zoomLevel < TILE_MIN_ZOOM_LEVEL ? parent.normalMat : parent.transMat; // UVs wrt Earth texture Vector2 tl = new Vector2((latLonTL.y + 180) / 360f, (latLonTL.x + 90) / 180f); Vector2 br = new Vector2((latLonBR.y + 180) / 360f, (latLonBR.x + 90) / 180f); if (tl.x > 0.5f && br.x < 0.5f) { br.x = 1f; } ti.worldTextureCoords = new Vector4(tl.x, br.y, br.x, tl.y); ti.ClearPlaceholderImage(); if (ti.zoomLevel < TILE_MIN_ZOOM_LEVEL) { ti.loadStatus = TILE_LOAD_STATUS.Loaded; } ti.texture = currentEarthTexture; ti.renderer = CreateObject(parentObj.transform, "Tile", tileCorners, tileIndices, tileUV, tileMat, ti.subquadIndex); ti.gameObject = ti.renderer.gameObject; ti.renderer.enabled = false; ti.created = true; #if DEBUG_TILES ti.gameObject.AddComponent <TileInfoEx> (); #endif }
void CheckTiles(TileInfo parent, int currentZoomLevel, int xTile, int yTile, int zoomLevel, int subquadIndex) { // Is this tile visible? TileInfo ti; int tileCode = GetTileHashCode(xTile, yTile, zoomLevel); if (!cachedTiles.TryGetValue(tileCode, out ti)) { ti = new TileInfo(xTile, yTile, zoomLevel, subquadIndex, currentEarthTexture); ti.parent = parent; if (parent != null) { if (parent.children == null) { parent.children = new List <TileInfo> (); } parent.children.Add(ti); } for (int k = 0; k < 4; k++) { Vector2 latlon = Conversion.GetLatLonFromTile(xTile + offsets [k].x, yTile + offsets [k].y, zoomLevel); ti.latlons [k] = latlon; Vector3 spherePos = Conversion.GetSpherePointFromLatLon(latlon); ti.spherePos [k] = spherePos; } cachedTiles [tileCode] = ti; } // Check if any tile corner is visible // Phase I #if DEBUG_TILES if (ti.gameObject != null && ti.gameObject.GetComponent <TileInfoEx> ().debug) { Debug.Log("this"); } #endif bool cornersOccluded = true; Vector3 minWorldPos = Misc.Vector3Max; Vector3 maxWorldPos = Misc.Vector3Min; Vector3 tmp = Misc.Vector3zero; for (int c = 0; c < 4; c++) { Vector3 wpos = transform.TransformPoint(ti.spherePos [c]); ti.cornerWorldPos [c] = wpos; if (wpos.x < minWorldPos.x) { minWorldPos.x = wpos.x; } if (wpos.y < minWorldPos.y) { minWorldPos.y = wpos.y; } if (wpos.z < minWorldPos.z) { minWorldPos.z = wpos.z; } if (wpos.x > maxWorldPos.x) { maxWorldPos.x = wpos.x; } if (wpos.y > maxWorldPos.y) { maxWorldPos.y = wpos.y; } if (wpos.z > maxWorldPos.z) { maxWorldPos.z = wpos.z; } if (cornersOccluded) { float radiusSqr = (wpos.x - globePos.x) * (wpos.x - globePos.x) + (wpos.y - globePos.y) * (wpos.y - globePos.y) + (wpos.z - globePos.z) * (wpos.z - globePos.z); // Vector3.SqrMagnitude (wpos - globePos); // Vector3 camDir = (currentCameraPosition - wpos).normalized; FastVector.NormalizedDirection(ref wpos, ref currentCameraPosition, ref tmp); // Vector3 st = wpos + ndir * (0.01f * transform.localScale.x); Vector3 st = wpos; FastVector.Add(ref st, ref tmp, localScaleFactor); float mag = (st.x - globePos.x) * (st.x - globePos.x) + (st.y - globePos.y) * (st.y - globePos.y) + (st.z - globePos.z) * (st.z - globePos.z); if (mag > radiusSqr) { cornersOccluded = false; } } } // Bounds bounds = new Bounds ((minWorldPos + maxWorldPos) * 0.5f, maxWorldPos - minWorldPos); FastVector.Average(ref minWorldPos, ref maxWorldPos, ref tmp); Bounds bounds = new Bounds(tmp, maxWorldPos - minWorldPos); Vector3 tileMidPoint = bounds.center; // Check center of quad if (cornersOccluded) { float radiusSqr = (tileMidPoint.x - globePos.x) * (tileMidPoint.x - globePos.x) + (tileMidPoint.y - globePos.y) * (tileMidPoint.y - globePos.y) + (tileMidPoint.z - globePos.z) * (tileMidPoint.z - globePos.z); // Vector3.SqrMagnitude (tileMidPoint - globePos); // Vector3 camDir = (currentCameraPosition - tileMidPoint).normalized; FastVector.NormalizedDirection(ref tileMidPoint, ref currentCameraPosition, ref tmp); // Vector3 st = tileMidPoint + tmp * (0.01f * transform.localScale.x); Vector3 st = tileMidPoint; FastVector.Add(ref st, ref tmp, localScaleFactor); float mag = (st.x - globePos.x) * (st.x - globePos.x) + (st.y - globePos.y) * (st.y - globePos.y) + (st.z - globePos.z) * (st.z - globePos.z); if (mag > radiusSqr) { cornersOccluded = false; } } #if DEBUG_TILES if (root == null) { root = new GameObject(); root.transform.SetParent(transform); root.transform.localPosition = Vector3.zero; root.transform.localRotation = Misc.QuaternionZero; //Quaternion.Euler (0, 0, 0); } #endif bool insideViewport = false; float minX = currentCamera.pixelWidth * 2f, minY = currentCamera.pixelHeight * 2f; float maxX = -minX, maxY = -minY; if (!cornersOccluded) { // Phase II for (int c = 0; c < 4; c++) { Vector3 scrPos = currentCamera.WorldToScreenPoint(ti.cornerWorldPos [c]); insideViewport = insideViewport || (scrPos.z > 0 && scrPos.x >= 0 && scrPos.x < currentCamera.pixelWidth && scrPos.y >= 0 && scrPos.y < currentCamera.pixelHeight); if (scrPos.x < minX) { minX = scrPos.x; } if (scrPos.x > maxX) { maxX = scrPos.x; } if (scrPos.y < minY) { minY = scrPos.y; } if (scrPos.y > maxY) { maxY = scrPos.y; } } if (!insideViewport) { insideViewport = GeometryUtility.TestPlanesAABB(cameraPlanes, bounds); } } ti.insideViewport = insideViewport; ti.visible = false; if (insideViewport) { if (!ti.created) { CreateTile(ti); } if (!ti.gameObject.activeSelf) { ti.gameObject.SetActive(true); } // Manage hierarchy of tiles bool tileIsBig = false; FastVector.NormalizedDirection(ref globePos, ref tileMidPoint, ref tmp); // float dd = Vector3.Dot (currentCameraForward, (tileMidPoint - globePos).normalized); float dd = Vector3.Dot(currentCameraForward, tmp); if (dd > -0.8f || currentZoomLevel > 9) // prevents big seams on initial zooms { float aparentSize = Mathf.Max(maxX - minX, maxY - minY); tileIsBig = aparentSize > currentTileSize; } else { tileIsBig = ti.zoomLevel < currentZoomLevel; } #if DEBUG_TILES if (ti.gameObject != null) { ti.gameObject.GetComponent <TileInfoEx> ().bigTile = tileIsBig; ti.gameObject.GetComponent <TileInfoEx> ().zoomLevel = ti.zoomLevel; } #endif if ((tileIsBig || zoomLevel < TILE_MIN_ZOOM_LEVEL) && zoomLevel < _tileMaxZoomLevel) { // Load nested tiles CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2, zoomLevel + 1, 0); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2, zoomLevel + 1, 1); CheckTiles(ti, currentZoomLevel, xTile * 2, yTile * 2 + 1, zoomLevel + 1, 2); CheckTiles(ti, currentZoomLevel, xTile * 2 + 1, yTile * 2 + 1, zoomLevel + 1, 3); ti.renderer.enabled = false; } else { ti.visible = true; // Show tile renderer if (!ti.renderer.enabled) { ti.renderer.enabled = true; } // If parent tile is loaded then use that as placeholder texture if (ti.zoomLevel > TILE_MIN_ZOOM_LEVEL && ti.parent.loadStatus == TILE_LOAD_STATUS.Loaded && !ti.placeholderImageSet) { ti.placeholderImageSet = true; ti.parentTextureCoords = placeHolderUV [ti.subquadIndex]; ti.SetPlaceholderImage(ti.parent.texture); } if (ti.loadStatus == TILE_LOAD_STATUS.Loaded) { if (!ti.hasAnimated) { ti.hasAnimated = true; ti.Animate(1f, AnimationEnded); } } else if (ti.loadStatus == TILE_LOAD_STATUS.Inactive) { ti.distToCamera = FastVector.SqrDistance(ref ti.cornerWorldPos [0], ref currentCameraPosition) * ti.zoomLevel; ti.loadStatus = TILE_LOAD_STATUS.InQueue; ti.queueTime = Time.time; loadQueue.Add(ti); } if (ti.children != null) { for (int k = 0; k < 4; k++) { TileInfo tiChild = ti.children [k]; HideTile(tiChild); } } } } else { HideTile(ti); } }