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; }
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 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)); }
/// <summary> /// Position and fit the spawner to the terrain /// </summary> public void FitToAllTerrains() { Terrain currentTerrain = GetCurrentTerrain(); if (currentTerrain == null) { Debug.LogError("Could not fit to terrain - no active terrain present"); return; } BoundsDouble b = new Bounds(); if (TerrainHelper.GetTerrainBounds(ref b)) { transform.position = b.center; m_settings.m_range = (float)b.extents.x; } }
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); }
//void OnEnable() //{ // if (m_gaiaSettings == null) // { // m_gaiaSettings = GaiaUtils.GetGaiaSettings(); // } //} /// <summary> /// Position and fit the spawner to the terrain /// </summary> public void FitToTerrain(Terrain t = null) { if (t == null) { t = Gaia.TerrainHelper.GetTerrain(transform.position, false); if (t == null) { t = Terrain.activeTerrain; } if (t == null) { Debug.LogWarning("Could not fit to terrain - no terrain present"); return; } } Bounds b = new Bounds(); if (TerrainHelper.GetTerrainBounds(t, ref b)) { transform.position = new Vector3(b.center.x, t.transform.position.y, b.center.z); m_settings.m_range = b.extents.x; } }
/// <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); } } } } }
/// <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); }
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); }