/// <summary> /// Updates the <see cref="TerrainQuad.ZMin"/> and <see cref="TerrainQuad.ZMax"/> values. /// Used to create a better fitting bounding box. /// Is not essental and can be disabled if retriving the heights data from the GPU is causing performance issues. /// </summary> private void UpdateMinMax() { // If no quads need read back or if disabled return if (NeedsReadBackDictionary.Count == 0 || !EnableReadBack) { return; } // Make a copy of all the keys of the tiles that need to be read back var ids = new Tile.Id[NeedsReadBackDictionary.Count]; NeedsReadBackDictionary.Keys.CopyTo(ids, 0); // Sort the keys by there level, lowest -> highest Array.Sort(ids, new Tile.ComparerID()); var count = 0; // Foreach key read back the tiles data until the maxReadBacksPerFrame limit is reached foreach (var id in ids) { var treeZ = NeedsReadBackDictionary[id]; // If elevations container already contains key then data has been read back before so just reapply the [min, max] values to TerranQuad if (ElevationsDicionary.ContainsKey(id)) { var info = ElevationsDicionary.Get(id); treeZ.TerrainQuad.ZMin = info.Min; treeZ.TerrainQuad.ZMax = info.Max; NeedsReadBackDictionary.Remove(id); } else { // If for some reason the tile is null remove from container and continue if (treeZ.Tile == null) { NeedsReadBackDictionary.Remove(id); continue; } var slot = treeZ.Tile.Slot[0] as GPUTileStorage.GPUSlot; // If for some reason this is not a GPUSlot remove and continue if (slot == null) { NeedsReadBackDictionary.Remove(id); continue; } var texture = slot.Texture; var size = texture.width * texture.height; var elevationInfo = new ElevationInfo(); elevationInfo.Elevations = new float[size]; // Read back heights data from texture CBUtility.ReadFromRenderTexture(texture, CBUtility.Channels.R, ElevationsBuffer, GodManager.Instance.ReadData); // Copy into elevations info ElevationsBuffer.GetData(elevationInfo.Elevations); // Find the min/max values for (int i = 0; i < size; i++) { if (elevationInfo.Elevations[i] < elevationInfo.Min) { elevationInfo.Min = elevationInfo.Elevations[i]; } if (elevationInfo.Elevations[i] > elevationInfo.Max) { elevationInfo.Max = elevationInfo.Elevations[i]; } } // Update TerrainQuad treeZ.TerrainQuad.ZMin = elevationInfo.Min; treeZ.TerrainQuad.ZMax = elevationInfo.Max; // Store elevations to prevent having to read back again soon // Add to end of container ElevationsDicionary.AddLast(id, elevationInfo); NeedsReadBackDictionary.Remove(id); count++; // If the number of rad back to do per frame has hit the limit stop loop. if (count >= MaxReadBacksPerFrame) { break; } } } // If the number of elevation info to store has exceded limit remove from start of container while (ElevationsDicionary.Count() > MaxStoredElevations) { ElevationsDicionary.RemoveFirst(); } }
/* * Updates the terrainQuads min and max values. Used to create a better fitting bounding box. * Is not essental and can be disabled if retriving the heights data from the GPU is causing * performance issues. */ void UpdateMinMax() { //if no quads need read back or if disabled return if(m_needReadBack.Count == 0 || !m_enableMinMaxReadBack) return; //Make a copy of all the keys of the tiles that need to be read back Tile.Id[] ids = new Tile.Id[m_needReadBack.Count]; m_needReadBack.Keys.CopyTo(ids, 0); //Sort the keys by there level, lowest -> highest System.Array.Sort(ids, new Tile.ComparerID()); int count = 0; //foreach key read back the tiles data until the maxReadBacksPerFrame limit is reached foreach(Tile.Id id in ids) { QuadTreeZ t = m_needReadBack[id]; //If elevations container already contains key then data has been //read back before so just reapply the min/max values to TerranQuad if(m_elevations.ContainsKey(id)) { ElevationInfo info = m_elevations.Get(id); t.quad.SetZMin(info.min); t.quad.SetZMax(info.max); m_needReadBack.Remove(id); } else { //if for some reason the tile is null remove from container and continue if(t.tile == null) { m_needReadBack.Remove(id); continue; } GPUTileStorage.GPUSlot slot = t.tile.GetSlot()[0] as GPUTileStorage.GPUSlot; //If for some reason this is not a GPUSlot remove and continue if(slot == null) { m_needReadBack.Remove(id); continue; } RenderTexture tex = slot.GetTexture(); int size = tex.width*tex.height; ElevationInfo info = new ElevationInfo(); info.elevations = new float[size]; //Read back heights data from texture CBUtility.ReadFromRenderTexture(tex, 1, m_elevationsBuffer, m_manager.GetReadData()); //Copy into elevations info m_elevationsBuffer.GetData(info.elevations); //Find the min/max values for(int i = 0; i < size; i++) { if(info.elevations[i] < info.min) info.min = info.elevations[i]; if(info.elevations[i] > info.max) info.max = info.elevations[i]; } //Update quad t.quad.SetZMin(info.min); t.quad.SetZMax(info.max); //Store elevations to prevent having to read back again soon //Add to end of container m_elevations.AddLast(id, info); m_needReadBack.Remove(id); count++; //If the number of rad back to do per frame has hit the limit stop loop. if(count >= m_maxReadBacksPerFrame) break; } } //If the number of elevation info to store has exceded limit remove from start of container while(m_elevations.Count() > m_maxStoredElevations) m_elevations.RemoveFirst(); }