/// <summary> /// Returns terrain names of terrains that intersect with the given bounds object /// </summary> /// <param name="bounds">A bounds object to check against the terrains. Needs to be in absolute world space position, mind the current origin offset!</param> /// <returns></returns> public static string[] GetTerrainsIntersectingBounds(BoundsDouble bounds) { //Reduce the bounds size a bit to prevent selecting terrains that are perfectly aligned with the bounds border //-this leads to too many terrains being logged as affected by an operation otherwise. Bounds intersectingBounds = new BoundsDouble(); intersectingBounds.center = bounds.center; intersectingBounds.size = bounds.size - new Vector3Double(0.001f, 0.001f, 0.001f); if (GaiaUtils.HasDynamicLoadedTerrains()) { GaiaSessionManager sessionManager = GaiaSessionManager.GetSessionManager(); if (sessionManager == null) { Debug.LogError("Trying to get terrains that intersect with bounds, but there is no session manager in scene."); return(null); } return(TerrainLoaderManager.TerrainScenes.Where(x => x.m_bounds.Intersects(intersectingBounds)).Select(x => x.GetTerrainName()).ToArray()); } else { List <string> affectedTerrainNames = new List <string>(); foreach (Terrain t in Terrain.activeTerrains) { if (intersectingBounds.Intersects(TerrainHelper.GetWorldSpaceBounds(t))) { affectedTerrainNames.Add(t.name); } } return(affectedTerrainNames.ToArray()); } }
public static Vector3 GetWorldCenter(bool sampleHeight = false) { BoundsDouble bounds = new BoundsDouble(); GetTerrainBounds(ref bounds); if (sampleHeight) { Terrain t = GetTerrain(bounds.center); if (t != null) { Vector3 centerOnTerrain = t.transform.position + new Vector3(t.terrainData.size.x / 2f, 0f, t.terrainData.size.z / 2f); float height = t.SampleHeight(centerOnTerrain); return(new Vector3(centerOnTerrain.x, height, centerOnTerrain.z)); } else { //No terrain? The user might be using mesh terrains then. Send out a raycast at the center to determine height RaycastHit raycastHit = new RaycastHit(); if (Physics.Raycast(new Vector3Double(bounds.center.x, 1000000f, bounds.center.z), Vector3.down, out raycastHit)) { return(raycastHit.point); } else { return(bounds.center); } } } else { return(new Vector3((float)bounds.center.x, (float)bounds.center.y, (float)bounds.center.z)); } }
public void OnWorldMapCreate() { m_worldMapTerrain = TerrainHelper.GetWorldMapTerrain(); GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings(); GaiaDefaults currentDefaults = gaiaSettings.m_currentDefaults; TerrainLoaderManager.Instance.TerrainSceneStorage.m_hasWorldMap = true; float worldheightmapRes = m_worldMapTerrain.terrainData.heightmapResolution / m_worldMapTerrain.terrainData.size.x; BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); if (bounds.size.x > 0) { TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize = (float)m_currentWorldCreationSettings.m_tileSize / (float)bounds.size.x; TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMapRelativeHeightmapPixels = (((float)bounds.size.x / m_localTileSize) * m_localHeightmapRes / m_localHeightmapRes); } else { //no bounds size means no real terrains (yet) - set these parameters according to the current settings/defaults then TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize = (float)m_currentWorldCreationSettings.m_tileSize / (gaiaSettings.m_tilesX * currentDefaults.m_terrainSize); TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMapRelativeHeightmapPixels = ((gaiaSettings.m_tilesX * currentDefaults.m_terrainSize) / currentDefaults.m_terrainSize) * currentDefaults.m_heightmapResolution / currentDefaults.m_heightmapResolution; } SyncLocalMapToWorldMap(); ShowWorldMapStampSpawner(); GaiaSessionManager.OnWorldCreated -= OnWorldMapCreate; }
private void CopyLocalMapToWorldMap(BoundsDouble bounds, Terrain t) { RenderTextureDescriptor rtDesc = t.terrainData.heightmapTexture.descriptor; rtDesc.width = Mathf.CeilToInt(m_worldMapTerrain.terrainData.heightmapResolution / ((float)bounds.size.x / t.terrainData.bounds.size.x)); rtDesc.height = rtDesc.width; RenderTexture chunkContent = RenderTexture.GetTemporary(rtDesc); float res = t.terrainData.heightmapResolution / rtDesc.width; Bounds worldSpaceBounds = t.terrainData.bounds; worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + t.transform.position.x, worldSpaceBounds.center.y + t.transform.position.y, worldSpaceBounds.center.z + t.transform.position.z); Vector2 pos = new Vector2(Mathf.InverseLerp(0, (float)bounds.size.x, Mathf.Abs((float)bounds.min.x - worldSpaceBounds.min.x)), Mathf.InverseLerp(0, (float)bounds.size.z, Mathf.Abs((float)bounds.min.z - worldSpaceBounds.min.z))); Graphics.Blit(t.terrainData.heightmapTexture, chunkContent, new Vector2(1, 1), new Vector2(0, 0)); RenderTexture previousRT = RenderTexture.active; RenderTexture.active = chunkContent; m_worldMapTerrain.terrainData.CopyActiveRenderTextureToHeightmap(new RectInt(0, 0, rtDesc.width, rtDesc.height), new Vector2Int(Mathf.FloorToInt(pos.x * m_worldMapTerrain.terrainData.heightmapResolution), Mathf.FloorToInt(pos.y * m_worldMapTerrain.terrainData.heightmapResolution)), t.drawInstanced ? TerrainHeightmapSyncControl.None : TerrainHeightmapSyncControl.HeightOnly); RenderTexture.active = previousRT; m_worldMapTerrain.terrainData.SyncHeightmap(); m_worldMapTerrain.editorRenderFlags = TerrainRenderFlags.All; RenderTexture.ReleaseTemporary(chunkContent); chunkContent = null; }
void OnDrawGizmosSelected() { #if UNITY_EDITOR if (Selection.activeObject == gameObject) { if (m_showBoundingBox) { Gizmos.color = Color.red; Gizmos.DrawWireCube(transform.position, new Vector3(m_settings.m_range * 2f, m_settings.m_range * 2f, m_settings.m_range * 2f)); } //Water if (m_showSeaLevelPlane && PWS_WaterSystem.Instance == null) { BoundsDouble bounds = new BoundsDouble(); if (TerrainHelper.GetTerrainBounds(ref bounds) == true) { bounds.center = new Vector3Double(bounds.center.x, SessionManager.GetSeaLevel(), bounds.center.z); bounds.size = new Vector3Double(bounds.size.x, 0.05f, bounds.size.z); Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 4f); Gizmos.DrawCube(bounds.center, bounds.size); } } } #endif }
private void CopyWorldMapToLocalMap(BoundsDouble bounds, Terrain t) { //make sure we have a world map terrain first if (m_worldMapTerrain == null) { m_worldMapTerrain = TerrainHelper.GetWorldMapTerrain(); } if (m_worldMapTerrain == null) { Debug.LogError("Can't export world map to local terrains - world map terrain is missing!"); return; } RenderTexture chunkContent = RenderTexture.GetTemporary(t.terrainData.heightmapTexture.descriptor); //FilterMode oldFilterMode = m_worldMapTerrain.terrainData.heightmapTexture.filterMode; //m_worldMapTerrain.terrainData.heightmapTexture.filterMode = FilterMode.Trilinear; //t.terrainData.heightmapTexture.filterMode = FilterMode.Trilinear; //chunkContent.filterMode = FilterMode.Trilinear; int maxTilesX = Mathf.RoundToInt((float)bounds.size.x / t.terrainData.size.x); int maxTilesZ = Mathf.RoundToInt((float)bounds.size.z / t.terrainData.size.z); int currentTileX = Mathf.RoundToInt((t.transform.position.x - (float)bounds.min.x) / t.terrainData.size.x); int currentTileZ = Mathf.RoundToInt((t.transform.position.z - (float)bounds.min.z) / t.terrainData.size.z); float res = (t.terrainData.heightmapResolution) / ((float)bounds.size.x / t.terrainData.bounds.size.x * (t.terrainData.heightmapResolution - 1)); Bounds worldSpaceBounds = t.terrainData.bounds; worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + t.transform.position.x, worldSpaceBounds.center.y + t.transform.position.y, worldSpaceBounds.center.z + t.transform.position.z); float xPos = ((float)currentTileX * t.terrainData.heightmapResolution) / (maxTilesX * t.terrainData.heightmapResolution); float zPos = ((float)currentTileZ * t.terrainData.heightmapResolution) / (maxTilesZ * t.terrainData.heightmapResolution); Vector2 pos = new Vector2(xPos, zPos); Graphics.Blit(m_worldMapTerrain.terrainData.heightmapTexture, chunkContent, new Vector2(res, res), pos); //m_worldMapTerrain.terrainData.heightmapTexture.filterMode = oldFilterMode; RenderTexture previousRT = RenderTexture.active; RenderTexture.active = chunkContent; t.terrainData.CopyActiveRenderTextureToHeightmap(new RectInt(0, 0, t.terrainData.heightmapResolution, t.terrainData.heightmapResolution), new Vector2Int(0, 0), t.drawInstanced ? TerrainHeightmapSyncControl.None : TerrainHeightmapSyncControl.HeightOnly); RenderTexture.active = previousRT; t.terrainData.SyncHeightmap(); t.editorRenderFlags = TerrainRenderFlags.All; RenderTexture.ReleaseTemporary(chunkContent); chunkContent = null; }
private Vector3 GetLocalStamperPosition() { BoundsDouble b = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref b); Transform worldmapTransform = transform.parent.parent; Terrain worldMapTerrain = worldmapTransform.GetComponent <Terrain>(); float relativeX = (transform.position.x - worldmapTransform.position.x) / worldMapTerrain.terrainData.size.x; float relativeZ = (transform.position.z - worldmapTransform.position.z) / worldMapTerrain.terrainData.size.z; float relativeY = transform.position.y / TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize; //TODO: Check if double precision required float newX = (float)b.min.x + (float)b.size.x * relativeX; float newZ = (float)b.min.z + (float)b.size.z * relativeZ; return(new Vector3(newX, relativeY, newZ)); }
public void SetLoadingRange(Double regularLoadingRange, Double impostorLoadingRange) { #if UNITY_EDITOR if (regularLoadingRange > 0 || impostorLoadingRange > 0) { Vector3Double targetLoadingExtentsRegular = new Vector3Double(regularLoadingRange, regularLoadingRange, regularLoadingRange); Vector3Double targetLoadingExtentsImpostor = new Vector3Double(impostorLoadingRange, impostorLoadingRange, impostorLoadingRange); BoundsDouble loadingBounds = m_sceneViewOriginLoadingBounds; if (m_centerSceneViewLoadingOn == CenterSceneViewLoadingOn.SceneViewCamera) { var allCameras = SceneView.GetAllSceneCameras(); if (allCameras.Length > 0) { if (m_sceneViewCameraLoadingBounds.center.Equals((Vector3Double)allCameras[0].transform.position) && m_sceneViewCameraLoadingBounds.extents.Equals(targetLoadingExtentsRegular) && m_sceneViewImpostorLoadingBounds.extents.Equals(targetLoadingExtentsImpostor)) { //this exact setup is what is already currently loaded, skip the rest of processing return; } m_sceneViewCameraLoadingBounds.center = (Vector3Double)allCameras[0].transform.position; } loadingBounds = m_sceneViewCameraLoadingBounds; } loadingBounds.extents = targetLoadingExtentsRegular; m_sceneViewOriginLoadingBounds.extents = loadingBounds.extents; m_sceneViewImpostorLoadingBounds.center = loadingBounds.center; m_sceneViewImpostorLoadingBounds.extents = targetLoadingExtentsImpostor; EditorUtility.SetDirty(this); UpdateTerrainLoadState(loadingBounds, m_sceneViewImpostorLoadingBounds, gameObject); } else { m_sceneViewOriginLoadingBounds.extents = Vector3.zero; m_sceneViewImpostorLoadingBounds.extents = Vector3.zero; foreach (TerrainScene ts in m_terrainSceneStorage.m_terrainScenes) { ts.RemoveRegularReference(gameObject); ts.RemoveImpostorReference(gameObject); } } #endif }
public void SyncLocalMapToWorldMap() { BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); if (GaiaUtils.HasDynamicLoadedTerrains()) { Action <Terrain> act = (t) => CopyLocalMapToWorldMap(bounds, t); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(act, false); } else { foreach (Terrain t in Terrain.activeTerrains) { if (t != m_worldMapTerrain) { CopyLocalMapToWorldMap(bounds, t); } } } }
public void SyncLocationFromStamperSettings() { BoundsDouble b = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref b); Transform worldmapTransform = transform.parent.parent; Terrain worldMapTerrain = worldmapTransform.GetComponent <Terrain>(); //TODO: review if this needs to be in double precision Vector3Double origin = TerrainLoaderManager.Instance.GetOrigin(); float relativeX = (float)(m_connectedStamperSettings.m_x - b.min.x + origin.x / TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize) / (float)b.size.x; float relativeY = (float)m_connectedStamperSettings.m_y * TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize; float relativeZ = (float)(m_connectedStamperSettings.m_z - b.min.z + origin.z / TerrainLoaderManager.Instance.TerrainSceneStorage.m_worldMaprelativeSize) / (float)b.size.z; //float relativeX = (float)(m_connectedStamperSettings.m_x - b.min.x) / (float)b.size.x; //float relativeY = (float) m_connectedStamperSettings.m_y * SessionManager.m_session.m_worldMaprelativeSize; //float relativeZ = (float)(m_connectedStamperSettings.m_z - b.min.z) / (float)b.size.z; float newX = worldmapTransform.position.x + worldMapTerrain.terrainData.size.x * relativeX; float newZ = worldmapTransform.position.z + worldMapTerrain.terrainData.size.z * relativeZ; transform.position = new Vector3(newX, relativeY, newZ); }
/// <summary> /// Syncs the heightmap of the world map to the local terrain tiles, preserving correct height scale, heightmap resolution, etc. /// </summary> /// <param name="validLocalTerrainNames">A list of local terrain tile names that are valid to change for the sync operation. If the list is null, all tiles will be assumed valid.</param> public void SyncWorldMapToLocalMap(List <string> validLocalTerrainNames = null) { BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); if (GaiaUtils.HasDynamicLoadedTerrains()) { Action <Terrain> act = (t) => CopyWorldMapToLocalMap(bounds, t); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(act, false, validLocalTerrainNames); } else { foreach (Terrain t in Terrain.activeTerrains) { if (t != m_worldMapTerrain) { if (validLocalTerrainNames == null || validLocalTerrainNames.Contains(t.name)) { CopyWorldMapToLocalMap(bounds, t); } } } } }
public RenderTexture BakeTerrainWorldBiomeMask(Terrain terrain, string worldBiomeMaskGUID) { if (m_gaiaSessionManager == null) { m_gaiaSessionManager = GaiaSessionManager.GetSessionManager(false); } if (m_worldMapTerrain == null) { m_worldMapTerrain = TerrainHelper.GetWorldMapTerrain(); } if (m_worldMapTerrain == null) { Debug.LogWarning("Found no world map terrain for baking a world biome mask."); return(null); } if (String.IsNullOrEmpty(worldBiomeMaskGUID)) { return(null); } if (m_gaiaSessionManager.m_session == null) { Debug.LogWarning("Found no session for baking a world biome mask."); return(null); } if (m_gaiaSessionManager.m_session.m_worldBiomeMaskSettings == null) { Debug.LogWarning("Found no world designer settings in the session for baking a world biome mask."); return(null); } //we need to apply the mask stack for this biome mask on the world map to get the result, then copy the appropiate rectangle for the queried terrain into the cache & return it. bool worldMapActiveState = m_worldMapTerrain.gameObject.activeInHierarchy; m_worldMapTerrain.gameObject.SetActive(true); GameObject emptyGO = new GameObject(); emptyGO.transform.position = new Vector3(m_worldMapTerrain.transform.position.x + m_worldMapTerrain.terrainData.size.x / 2f, m_worldMapTerrain.transform.position.y, m_worldMapTerrain.transform.position.z + +m_worldMapTerrain.terrainData.size.z / 2f); GaiaMultiTerrainOperation operation = new GaiaMultiTerrainOperation(m_worldMapTerrain, emptyGO.transform, m_worldMapTerrain.terrainData.size.x); operation.m_isWorldMapOperation = true; operation.GetHeightmap(); operation.GetNormalmap(); operation.CollectTerrainBakedMasks(); RenderTextureDescriptor rtDescriptor = operation.RTbakedMask.descriptor; RenderTexture inputTexture = RenderTexture.GetTemporary(rtDescriptor); RenderTexture currentRT = RenderTexture.active; RenderTexture.active = inputTexture; GL.Clear(true, true, Color.white); RenderTexture.active = currentRT; RenderTexture ruleOutputTexture = RenderTexture.GetTemporary(rtDescriptor); ImageMask[] maskStack = m_gaiaSessionManager.m_session.m_worldBiomeMaskSettings.m_spawnerRules.Find(x => x.GUID == worldBiomeMaskGUID).m_imageMasks; //Calculate Target position &/ resolution BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); bounds.center -= TerrainLoaderManager.Instance.GetOrigin(); RenderTexture chunkContent = new RenderTexture(terrain.terrainData.heightmapTexture.descriptor); int maxTilesX = Mathf.RoundToInt((float)bounds.size.x / terrain.terrainData.size.x); int maxTilesZ = Mathf.RoundToInt((float)bounds.size.z / terrain.terrainData.size.z); int currentTileX = Mathf.RoundToInt((terrain.transform.position.x - (float)bounds.min.x) / terrain.terrainData.size.x); int currentTileZ = Mathf.RoundToInt((terrain.transform.position.z - (float)bounds.min.z) / terrain.terrainData.size.z); float res = (terrain.terrainData.heightmapResolution) / ((float)bounds.size.x / terrain.terrainData.bounds.size.x * (terrain.terrainData.heightmapResolution - 1)); Bounds worldSpaceBounds = terrain.terrainData.bounds; worldSpaceBounds.center = new Vector3(worldSpaceBounds.center.x + terrain.transform.position.x, worldSpaceBounds.center.y + terrain.transform.position.y, worldSpaceBounds.center.z + terrain.transform.position.z); float xPos = ((float)currentTileX * terrain.terrainData.heightmapResolution) / (maxTilesX * terrain.terrainData.heightmapResolution); float zPos = ((float)currentTileZ * terrain.terrainData.heightmapResolution) / (maxTilesZ * terrain.terrainData.heightmapResolution); Vector2 pos = new Vector2(xPos, zPos); //If we have a mask stack, we need to process it if (maskStack != null && maskStack.Length > 0) { //We start from a white texture, so we need the first mask action in the stack to always be "Multiply", otherwise there will be no result. maskStack[0].m_blendMode = ImageMaskBlendMode.Multiply; float maxWorldHeight = 0f; float minWorldHeight = 0f; m_gaiaSessionManager.GetWorldMinMax(ref minWorldHeight, ref maxWorldHeight, true); //Iterate through all image masks and set up the current paint context in case the shader uses heightmap data foreach (ImageMask mask in maskStack) { mask.m_multiTerrainOperation = operation; mask.m_seaLevel = m_gaiaSessionManager.GetSeaLevel(true); mask.m_maxWorldHeight = maxWorldHeight; mask.m_minWorldHeight = minWorldHeight; } Graphics.Blit(ImageProcessing.ApplyMaskStack(inputTexture, ruleOutputTexture, maskStack, ImageMaskInfluence.Local), ruleOutputTexture); } else { //no mask stack -> just blit the white input texture over as the output Graphics.Blit(inputTexture, ruleOutputTexture); } operation.CloseOperation(); DestroyImmediate(emptyGO); RenderTexture.ReleaseTemporary(inputTexture); m_worldMapTerrain.gameObject.SetActive(worldMapActiveState); //copy the rule output into the right size for the requested terrain chunk Graphics.Blit(ruleOutputTexture, chunkContent, new Vector2(res, res), pos); string filename = GetWorldBiomeMaskFilename(terrain, worldBiomeMaskGUID); SaveBakedMaskInCache(chunkContent, terrain, filename); RenderTexture.ReleaseTemporary(ruleOutputTexture); return(chunkContent); }
/// <summary> /// Get the bounds of the terrain at this location or fail with a null /// </summary> /// <param name="locationWU">Location to check and get terrain for</param> /// <returns>Bounds of selected terrain or null if invalid for some reason</returns> public static bool GetTerrainBounds(ref BoundsDouble bounds, bool activeTerrainsOnly = false) { //Terrain terrain = GetTerrain(locationWU); //if (terrain == null) //{ // return false; //} //bounds.center = terrain.transform.position; //bounds.size = terrain.terrainData.size; //bounds.center += bounds.extents; Vector3Double accumulatedCenter = new Vector3Double(); //Do we use dynamic loaded terrains in the scene? if (GaiaUtils.HasDynamicLoadedTerrains() && !activeTerrainsOnly) { #if GAIA_PRO_PRESENT //we do have dynamic terrains -> calculate the bounds according to the terrain scene data in the session GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(false); foreach (TerrainScene t in TerrainLoaderManager.TerrainScenes) { accumulatedCenter += t.m_bounds.center; } bounds.center = accumulatedCenter / TerrainLoaderManager.TerrainScenes.Count; foreach (TerrainScene t in TerrainLoaderManager.TerrainScenes) { bounds.Encapsulate(t.m_bounds); } #endif } else { //no placeholder -> calculate bounds according to the active terrains in the scene if (Terrain.activeTerrains.Length > 0) { foreach (Terrain t in Terrain.activeTerrains) { if (!TerrainHelper.IsWorldMapTerrain(t)) { if (t.terrainData != null) { accumulatedCenter += new Vector3Double(t.transform.position) + new Vector3Double(t.terrainData.bounds.extents); } else { Debug.LogWarning("Terrain " + t.name + " in the scene is missing the terrain data object!"); } } } bounds.center = accumulatedCenter / Terrain.activeTerrains.Length; foreach (Terrain t in Terrain.activeTerrains) { if (!TerrainHelper.IsWorldMapTerrain(t)) { if (t.terrainData != null) { Bounds newBounds = new Bounds(); newBounds.center = t.transform.position; newBounds.size = t.terrainData.size; newBounds.center += t.terrainData.bounds.extents; bounds.Encapsulate(newBounds); } } } } else { bounds = new BoundsDouble(Vector3Double.zero, Vector3Double.zero); //No active terrains? There might be mesh terrains we can use then GameObject meshTerrainExportObject = GaiaUtils.GetTerrainExportObject(false); if (meshTerrainExportObject != null) { foreach (Transform t in meshTerrainExportObject.transform) { MeshRenderer mr = t.GetComponent <MeshRenderer>(); if (mr != null) { bounds.Encapsulate(mr.bounds); } } } } } return(true); }
/// <summary> /// Load and unload the terrain scenes stored in the current session for a certain object /// </summary> public void UpdateTerrainLoadState(BoundsDouble loadingBoundsRegular = null, BoundsDouble loadingBoundsImpostor = null, GameObject requestingObject = null, float minDistance = 0, float maxDistance = 0, float minThresholdMS = 0, float maxThresholdMS = 0) { //Do not accept changes to load state during runtime when there was no runtime init yet if (Application.isPlaying && !m_runtimeInitialized) { return; } //Do not perform any updates when terrain loading is disabled per default #if GAIA_PRO_PRESENT if (TerrainLoaderManager.Instance.m_terrainSceneStorage == null || !TerrainLoaderManager.Instance.m_terrainSceneStorage.m_terrainLoadingEnabled) { return; } #endif if (requestingObject == null) { requestingObject = gameObject; } long currentTimeStamp = GaiaUtils.GetUnixTimestamp(); m_terrainSceneActionQueue.Clear(); foreach (TerrainScene terrainScene in TerrainLoaderManager.TerrainScenes) { if (terrainScene.m_nextUpdateTimestamp > currentTimeStamp) { continue; } float distance = Vector3.Distance(terrainScene.m_bounds.center - terrainScene.m_currentOriginOffset, requestingObject.transform.position); terrainScene.m_currentOriginOffset = m_sceneViewOriginLoadingBounds.center; bool wasChanged = false; //only evaluate load state if local terrain is supposed to be displayed if (m_showLocalTerrain) { if (loadingBoundsImpostor != null && loadingBoundsImpostor.extents.magnitude > 0 && loadingBoundsImpostor.extents.magnitude > loadingBoundsRegular.extents.magnitude) { if (terrainScene.m_bounds.Intersects(loadingBoundsImpostor) && !TerrainSceneStorage.m_colliderOnlyLoading) { if (!terrainScene.HasImpostorReference(requestingObject) || terrainScene.m_impostorLoadState == LoadState.Unloaded) { //terrainScene.AddImpostorReference(requestingObject); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.AddImpostorReference, distance); terrainScene.m_useFloatingPointFix = m_terrainSceneStorage.m_useFloatingPointFix; wasChanged = true; } } else { if (terrainScene.HasImpostorReference(requestingObject) || terrainScene.m_impostorLoadState == LoadState.Loaded) { //terrainScene.RemoveImpostorReference(requestingObject, m_cacheMemoryThreshold); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.RemoveImpostorReference, distance); wasChanged = true; } if (terrainScene.m_impostorLoadState == LoadState.Cached && (!CachingAllowed() || terrainScene.m_impostorCachedTimestamp + m_cacheKeepAliveTime < currentTimeStamp)) { //terrainScene.RemoveImpostorReference(requestingObject, m_cacheMemoryThreshold, true); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.RemoveImpostorReference, distance, true); } } } else { if (terrainScene.HasImpostorReference(requestingObject)) { //terrainScene.RemoveImpostorReference(requestingObject, m_cacheMemoryThreshold); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.RemoveImpostorReference, distance); wasChanged = true; } } if (loadingBoundsRegular != null && loadingBoundsRegular.extents.magnitude > 0) { if (terrainScene.m_bounds.Intersects(loadingBoundsRegular)) { if (!terrainScene.HasRegularReference(requestingObject) || terrainScene.m_regularLoadState == LoadState.Unloaded) { //terrainScene.AddRegularReference(requestingObject); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.AddRegularReference, distance); terrainScene.m_useFloatingPointFix = m_terrainSceneStorage.m_useFloatingPointFix; wasChanged = true; } } else { if (terrainScene.HasRegularReference(requestingObject) || terrainScene.m_regularLoadState == LoadState.Loaded) { //terrainScene.RemoveRegularReference(requestingObject, m_cacheMemoryThreshold); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.RemoveRegularReference, distance); wasChanged = true; } if (terrainScene.m_regularLoadState == LoadState.Cached && (!CachingAllowed() || terrainScene.m_regularCachedTimestamp + m_cacheKeepAliveTime < currentTimeStamp)) { //terrainScene.RemoveRegularReference(requestingObject, m_cacheMemoryThreshold, true); AddToTerrainSceneActionQueue(terrainScene, ReferenceChange.RemoveRegularReference, distance, true); } } } } terrainScene.ShiftLoadedTerrain(); if (Application.isPlaying && !wasChanged) { long threshold = +(long)Mathf.Lerp(minThresholdMS, maxThresholdMS, Mathf.InverseLerp(minDistance, maxDistance, Vector3.Distance(loadingBoundsRegular.center, terrainScene.m_bounds.center))) + UnityEngine.Random.Range(10, 50); terrainScene.m_nextUpdateTimestamp = currentTimeStamp + threshold; } else { terrainScene.m_nextUpdateTimestamp = 0; } } for (int i = 0; i < m_terrainSceneActionQueue.Count; i++) { switch (m_terrainSceneActionQueue[i].m_referenceChange) { case ReferenceChange.AddImpostorReference: m_terrainSceneActionQueue[i].m_terrainScene.AddImpostorReference(requestingObject); break; case ReferenceChange.AddRegularReference: m_terrainSceneActionQueue[i].m_terrainScene.AddRegularReference(requestingObject); break; case ReferenceChange.RemoveImpostorReference: m_terrainSceneActionQueue[i].m_terrainScene.RemoveImpostorReference(requestingObject, m_cacheMemoryThreshold, m_terrainSceneActionQueue[i].m_forced); break; case ReferenceChange.RemoveRegularReference: m_terrainSceneActionQueue[i].m_terrainScene.RemoveRegularReference(requestingObject, m_cacheMemoryThreshold, m_terrainSceneActionQueue[i].m_forced); break; } } }
public void LoadStorageData() { #if UNITY_EDITOR //Try to get the terrain scene storage file from the last used GUID first if (!String.IsNullOrEmpty(m_lastUsedGUID)) { m_terrainSceneStorage = (TerrainSceneStorage)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(m_lastUsedGUID), typeof(TerrainSceneStorage)); } //No guid / storage object? Then we need to create one in the current session directory if (m_terrainSceneStorage == null) { GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(); if (gsm != null && gsm.m_session != null) { string path = GaiaDirectories.GetScenePath(gsm.m_session) + "/TerrainScenes.asset"; if (File.Exists(path)) { m_terrainSceneStorage = (TerrainSceneStorage)AssetDatabase.LoadAssetAtPath(path, typeof(TerrainSceneStorage)); } else { m_terrainSceneStorage = ScriptableObject.CreateInstance <TerrainSceneStorage>(); if (TerrainHelper.GetWorldMapTerrain() != null) { m_terrainSceneStorage.m_hasWorldMap = true; } AssetDatabase.CreateAsset(m_terrainSceneStorage, path); AssetDatabase.ImportAsset(path); } } else { m_terrainSceneStorage = ScriptableObject.CreateInstance <TerrainSceneStorage>(); } } //Check if there are scene files existing already and if they are in the storage data - if not, we should pick them up accordingly string directory = GaiaDirectories.GetTerrainScenePathForStorageFile(m_terrainSceneStorage); var dirInfo = new DirectoryInfo(directory); bool madeChanges = false; if (dirInfo != null) { FileInfo[] allFiles = dirInfo.GetFiles(); foreach (FileInfo fileInfo in allFiles) { if (fileInfo.Extension == ".unity") { string path = GaiaDirectories.GetPathStartingAtAssetsFolder(fileInfo.FullName); if (!m_terrainSceneStorage.m_terrainScenes.Exists(x => x.GetTerrainName() == x.GetTerrainName(path))) { string firstSegment = fileInfo.Name.Split('-')[0]; int xCoord = -99; int zCoord = -99; bool successX, successZ; try { successX = Int32.TryParse(firstSegment.Substring(firstSegment.IndexOf('_') + 1, firstSegment.LastIndexOf('_') - (firstSegment.IndexOf('_') + 1)), out xCoord); successZ = Int32.TryParse(firstSegment.Substring(firstSegment.LastIndexOf('_') + 1, firstSegment.Length - 1 - firstSegment.LastIndexOf('_')), out zCoord); } catch (Exception ex) { if (ex.Message == "123") { } successX = false; successZ = false; } if (successX && successZ) { //double centerX = (xCoord - (m_terrainSceneStorage.m_terrainTilesX / 2f)) * m_terrainSceneStorage.m_terrainTilesSize + (m_terrainSceneStorage.m_terrainTilesSize /2f); //double centerZ = (zCoord - (m_terrainSceneStorage.m_terrainTilesZ / 2f)) * m_terrainSceneStorage.m_terrainTilesSize + (m_terrainSceneStorage.m_terrainTilesSize / 2f); Vector2 offset = new Vector2(-m_terrainSceneStorage.m_terrainTilesSize * m_terrainSceneStorage.m_terrainTilesX * 0.5f, -m_terrainSceneStorage.m_terrainTilesSize * m_terrainSceneStorage.m_terrainTilesZ * 0.5f); Vector3Double position = new Vector3(m_terrainSceneStorage.m_terrainTilesSize * xCoord + offset.x, 0, m_terrainSceneStorage.m_terrainTilesSize * zCoord + offset.y); Vector3Double center = new Vector3Double(position + new Vector3Double(m_terrainSceneStorage.m_terrainTilesSize / 2f, 0f, m_terrainSceneStorage.m_terrainTilesSize / 2f)); BoundsDouble bounds = new BoundsDouble(center, new Vector3Double(m_terrainSceneStorage.m_terrainTilesSize, m_terrainSceneStorage.m_terrainTilesSize * 4, m_terrainSceneStorage.m_terrainTilesSize)); //Use forward slashes in the path - The Unity scene management classes expect it that way path = path.Replace("\\", "/"); TerrainScene terrainScene = new TerrainScene() { m_scenePath = path, m_pos = position, m_bounds = bounds, m_useFloatingPointFix = m_terrainSceneStorage.m_useFloatingPointFix }; if (File.Exists(path.Replace("Terrain", GaiaConstants.ImpostorTerrainName))) { terrainScene.m_impostorScenePath = path.Replace("Terrain", GaiaConstants.ImpostorTerrainName); } if (File.Exists(path.Replace("Terrain", "Collider"))) { terrainScene.m_colliderScenePath = path.Replace("Terrain", "Collider"); } if (File.Exists(path.Replace("Terrain", "Backup"))) { terrainScene.m_backupScenePath = path.Replace("Terrain", "Backup"); } m_terrainSceneStorage.m_terrainScenes.Add(terrainScene); madeChanges = true; } } } } if (madeChanges) { EditorUtility.SetDirty(m_terrainSceneStorage); AssetDatabase.SaveAssets(); } } m_lastUsedGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_terrainSceneStorage)); RefreshTerrainsWithCurrentData(); RefreshSceneViewLoadingRange(); ////Go over the currently open scene and close the ones that do not seem to have a reference on them //for (int i = EditorSceneManager.loadedSceneCount-1; i >= 0; i--) //{ // Scene scene = EditorSceneManager.GetSceneAt(i); // if (EditorSceneManager.GetActiveScene().Equals(scene)) // { // continue; // } // TerrainScene terrainScene = m_terrainSceneStorage.m_terrainScenes.Find(x => x.m_scenePath == scene.path || x.m_impostorScenePath == scene.path || x.m_colliderScenePath == scene.path); // if (terrainScene != null) // { // terrainScene.UpdateWithCurrentData(); // } // else // { // EditorSceneManager.UnloadSceneAsync(scene); // } //} #endif }
public void Encapsulate(BoundsDouble bounds) { this.Encapsulate(bounds.center - bounds.extents); this.Encapsulate(bounds.center + bounds.extents); }
/// <summary> /// Draw gizmos /// </summary> void OnDrawGizmos() { if (m_resources == null) { return; } if (m_spawner == null) { return; } if (m_terrainHeightMap == null) { return; } //Lets visualise fitness float x, y = transform.position.y, z; float xStart = transform.position.x - m_range; float xEnd = transform.position.x + m_range; float zStart = transform.position.z - m_range; float zEnd = transform.position.z + m_range; float ballsize = Mathf.Clamp(m_resolution * 0.25f, 0.5f, 5f); m_spawner.m_settings.m_spawnRange = m_range; m_spawner.m_spawnerBounds = new Bounds(transform.position, new Vector3(m_range * 2f, m_range * 20f, m_range * 2f)); SpawnInfo spawnInfo = new SpawnInfo(); Vector3 location = new Vector3(); float fitness = 0f; //Create caches if ((DateTime.Now - m_lastCacheUpdateDate).TotalSeconds > 5) { m_lastCacheUpdateDate = DateTime.Now; m_spawner.DeleteSpawnCaches(); m_spawner.CreateSpawnCaches(m_selectedResourceType, m_selectedResourceIdx); //Also update the location so make moving it easier Terrain terrain = TerrainHelper.GetTerrain(transform.position); if (terrain != null) { transform.position = new Vector3(transform.position.x, terrain.SampleHeight(transform.position) + 5f, transform.position.z); } } //Set up the texture layer array in spawn info spawnInfo.m_textureStrengths = new float[Terrain.activeTerrain.terrainData.alphamapLayers]; //Now visualise fitness for (x = xStart; x < xEnd; x += m_resolution) { for (z = zStart; z < zEnd; z += m_resolution) { location.Set(x, y, z); if (m_spawner.CheckLocation(location, ref spawnInfo)) { fitness = GetFitness(ref spawnInfo); if (fitness < m_minimumFitness) { continue; } Gizmos.color = Color.Lerp(m_unfitColour, m_fitColour, fitness); Gizmos.DrawSphere(spawnInfo.m_hitLocationWU, ballsize); } } } //Now draw water //Water if (m_resources != null) { BoundsDouble bounds = new BoundsDouble(); if (TerrainHelper.GetTerrainBounds(ref bounds) == true) { bounds.center = new Vector3Double(bounds.center.x, GaiaSessionManager.GetSessionManager().GetSeaLevel(), bounds.center.z); bounds.size = new Vector3Double(bounds.size.x, 0.05f, bounds.size.z); Gizmos.color = new Color(Color.blue.r, Color.blue.g, Color.blue.b, Color.blue.a / 4f); Gizmos.DrawCube(bounds.center, bounds.size); } } }
public void CreateWorldMapTerrain() { //Remove old world map terrain, if any Terrain oldWMTerrain = TerrainHelper.GetWorldMapTerrain(); if (oldWMTerrain != null) { #if UNITY_EDITOR if (EditorUtility.DisplayDialog("Delete old world map?", "You are about to create a new world map in this scene. This will delete the existing world map and the stamp tokens on it. This will only affect the small world map terrain, the actual full scene terrain tiles will not be removed. Continue?", "Continue", "Cancel")) { DestroyImmediate(oldWMTerrain.gameObject); } else { return; } #else Destroy(oldWMTerrain.gameObject); #endif } GaiaSettings gaiaSettings = GaiaUtils.GetGaiaSettings(); GaiaDefaults currentDefaults = gaiaSettings.m_currentDefaults; GaiaSessionManager gsm = GaiaSessionManager.GetSessionManager(); //Collect some info from the existing world, if any. //We need the average height from the terrains to create the height of the worldmap accordingly in scale double averageHeight = currentDefaults.m_terrainHeight; //We need the heightmap resolution and terrain size stored in the session //To properly scale between world map and local map even when one of the two is not loaded at the moment int count = 0; foreach (Terrain t in Terrain.activeTerrains) { averageHeight += t.terrainData.size.y; if (!TerrainHelper.IsWorldMapTerrain(t)) { m_localHeightmapRes = t.terrainData.heightmapResolution; m_localTileSize = t.terrainData.size.x; } count++; } //} //only calculate an average if there is at least one placeholder or terrain if (count > 0) { averageHeight /= count; } BoundsDouble bounds = new BoundsDouble(); TerrainHelper.GetTerrainBounds(ref bounds); //Collect the new world settings for world creation WorldCreationSettings worldCreationSettings = ScriptableObject.CreateInstance <WorldCreationSettings>(); worldCreationSettings.m_xTiles = 1; worldCreationSettings.m_zTiles = 1; worldCreationSettings.m_tileSize = (count > 0) ? Mathd.RoundToInt(bounds.size.x) : gaiaSettings.m_tilesX * currentDefaults.m_terrainSize; worldCreationSettings.m_tileHeight = currentDefaults.m_terrainHeight; worldCreationSettings.m_createInScene = false; worldCreationSettings.m_autoUnloadScenes = false; worldCreationSettings.m_applyFloatingPointFix = false; worldCreationSettings.m_applyFloatingPointFix = false; worldCreationSettings.m_centerOffset = Vector3.zero; //(count > 0) ? new Vector2Double(bounds.center.x + bounds.extents.x + worldCreationSettings.m_tileSize, bounds.center.z) : Vector2Double.zero; worldCreationSettings.m_isWorldMap = true; //clone defaults so we can inject our custom heightmap resolution for the worldmap GaiaDefaults clonedDefaults = Instantiate(currentDefaults); clonedDefaults.m_heightmapResolution = (int)m_heightmapResolution; worldCreationSettings.m_gaiaDefaults = clonedDefaults; m_currentWorldCreationSettings = worldCreationSettings; GaiaSessionManager.OnWorldCreated -= OnWorldMapCreate; GaiaSessionManager.OnWorldCreated += OnWorldMapCreate; GaiaSessionManager.CreateWorld(worldCreationSettings); }