/// <summary> /// Updates the ground height below camera. /// </summary> private void UpdateGroundHeight() { if (TerrainNode.LocalCameraPosition.z > TerrainNode.TerrainQuadRoot.ZMax) { return; } var localCameraPosition = TerrainNode.LocalCameraPosition; // If camera has moved update ground height if ((localCameraPosition - OldLocalCamera).Magnitude() > 1.0 && CameraQuad != null && CameraQuad.Tile != null && EnableGroundHeightUpdate) { var slot = CameraQuad.Tile.Slot[0] as GPUTileStorage.GPUSlot; if (slot != null) { var border = Producer.GetBorder(); var tileSize = Producer.GetTileSizeMinBorder(0); var dx = CameraQuadCoordinates.x * tileSize; var dy = CameraQuadCoordinates.y * tileSize; // x,y are the non-normalized position in the elevations texture where the ground height below the camera is. var x = dx + (float)border; var y = dy + (float)border; // Read the single value from the render texture CBUtility.ReadSingleFromRenderTexture(slot.Texture, x, y, 0, GroundBuffer, GodManager.Instance.ReadData, true); // Get single height value from buffer var height = new Vector4[1]; GroundBuffer.GetData(height); TerrainNode.ParentBody.HeightZ = Math.Max(0.0, height[0].x); OldLocalCamera.x = localCameraPosition.x; OldLocalCamera.y = localCameraPosition.y; OldLocalCamera.z = localCameraPosition.z; } } CameraQuad = null; }
protected override void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad) { if (tree == null) { tree = new QuadTreeZ(parent, quad); tree.IsNeedTile = NeedTile(quad); } var treeZ = tree as QuadTreeZ; if (treeZ == null) { Debug.LogError("TileSamplerZ.GetTiles: Can't get provided tree as QuadTreeZ!"); base.GetTiles(parent, ref tree, quad); return; } // If tile needs elevation data read back add to container if (treeZ.Tile != null && treeZ.Tile.Task.IsDone && !treeZ.ReadBack && MaxReadBacksPerFrame > 0) { if (!NeedsReadBackDictionary.ContainsKey(treeZ.Tile.ID)) { treeZ.ReadBack = true; NeedsReadBackDictionary.Add(treeZ.Tile.ID, treeZ); } } base.GetTiles(parent, ref tree, quad); // Check if this TerrainQuad is below the camera. If so store a reference to it. if (CameraQuad == null && treeZ.Tile != null && treeZ.Tile.Task.IsDone) { var cameraPosition = quad.Owner.LocalCameraPosition; var l = quad.Length; var ox = quad.Ox; var oy = quad.Oy; if (cameraPosition.x >= ox && cameraPosition.x < ox + l && cameraPosition.y >= oy && cameraPosition.y < oy + l) { CameraQuadCoordinates = new Vector2((float)((cameraPosition.x - ox) / l), (float)((cameraPosition.y - oy) / l)); CameraQuad = treeZ; } } }
protected override void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad) { if (tree == null) { tree = new QuadTreeZ(parent, quad); tree.needTile = NeedTile(quad); } QuadTreeZ t = tree as QuadTreeZ; //If tile needs elevation data read back add to container if (t.tile != null && t.tile.GetTask().IsDone() && !t.readBack && m_maxReadBacksPerFrame > 0) { if (!m_needReadBack.ContainsKey(t.tile.GetId())) { t.readBack = true; m_needReadBack.Add(t.tile.GetId(), t); } } base.GetTiles(parent, ref tree, quad); //Check if this quad is below the camera. If so store a reference to it. if (m_cameraQuad == null && t.tile != null && t.tile.GetTask().IsDone()) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); double l = quad.GetLength(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { m_cameraQuadCoords = new Vector2((float)((c.x - ox) / l), (float)((c.y - oy) / l)); m_cameraQuad = t; } } }
/* * Updates the ground height below camera. */ void UpdateGroundHeight() { Vector3d2 localCamPos = GetTerrainNode().GetLocalCameraPos(); //If camera has moved update ground height if ((localCamPos - m_oldLocalCamera).Magnitude() > 1.0 && m_cameraQuad != null && m_cameraQuad.tile != null) { GPUTileStorage.GPUSlot slot = m_cameraQuad.tile.GetSlot()[0] as GPUTileStorage.GPUSlot; if (slot != null) { int border = GetProducer().GetBorder(); int tileSize = GetProducer().GetTileSizeMinBorder(0); float dx = m_cameraQuadCoords.x * tileSize; float dy = m_cameraQuadCoords.y * tileSize; //x,y are the non-normalized position in the elevations texture where the //ground height below the camera is. float x = dx + (float)border; float y = dy + (float)border; //Read the single value from the render texture CBUtility.ReadSingleFromRenderTexture(slot.GetTexture(), x, y, 0, m_groundBuffer, m_manager.GetReadData(), true); //Get single height value from buffer float[] height = new float[1]; m_groundBuffer.GetData(height); //Update the ground height. Stored as a static value in the TerrainNode script GetView().SetGroundHeight(Math.Max(0.0, height[0])); m_oldLocalCamera.x = localCamPos.x; m_oldLocalCamera.y = localCamPos.y; m_oldLocalCamera.z = localCamPos.z; } } m_cameraQuad = null; }
/// <summary> /// 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. /// </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) { QuadTreeZ 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)) { ElevationInfo 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, 1, 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(); } }
protected override void GetTiles(QuadTree parent, ref QuadTree tree, TerrainQuad quad) { if (tree == null) { tree = new QuadTreeZ(parent, quad); tree.needTile = NeedTile(quad); } QuadTreeZ t = tree as QuadTreeZ; //If tile needs elevation data read back add to container if(t.tile != null && t.tile.GetTask().IsDone() && !t.readBack && m_maxReadBacksPerFrame > 0) { if(!m_needReadBack.ContainsKey(t.tile.GetId())) { t.readBack = true; m_needReadBack.Add(t.tile.GetId(), t); } } base.GetTiles(parent, ref tree, quad); //Check if this quad is below the camera. If so store a reference to it. if (m_cameraQuad == null && t.tile != null && t.tile.GetTask().IsDone()) { Vector3d2 c = quad.GetOwner().GetLocalCameraPos(); double l = quad.GetLength(); double ox = quad.GetOX(); double oy = quad.GetOY(); if (c.x >= ox && c.x < ox + l && c.y >= oy && c.y < oy + l) { m_cameraQuadCoords = new Vector2((float)((c.x - ox) / l), (float)((c.y - oy) / l)); m_cameraQuad = t; } } }
/* * Updates the ground height below camera. */ void UpdateGroundHeight() { Vector3d2 localCamPos = GetTerrainNode().GetLocalCameraPos(); //If camera has moved update ground height if ((localCamPos - m_oldLocalCamera).Magnitude() > 1.0 && m_cameraQuad != null && m_cameraQuad.tile != null) { GPUTileStorage.GPUSlot slot = m_cameraQuad.tile.GetSlot()[0] as GPUTileStorage.GPUSlot; if(slot != null) { int border = GetProducer().GetBorder(); int tileSize = GetProducer().GetTileSizeMinBorder(0); float dx = m_cameraQuadCoords.x * tileSize; float dy = m_cameraQuadCoords.y * tileSize; //x,y are the non-normalized position in the elevations texture where the //ground height below the camera is. float x = dx + (float)border; float y = dy + (float)border; //Read the single value from the render texture CBUtility.ReadSingleFromRenderTexture(slot.GetTexture(), x, y, 0, m_groundBuffer, m_manager.GetReadData(), true); //Get single height value from buffer float[] height = new float[1]; m_groundBuffer.GetData(height); //Update the ground height. Stored as a static value in the TerrainNode script GetView().SetGroundHeight(Math.Max(0.0, height[0])); m_oldLocalCamera.x = localCamPos.x; m_oldLocalCamera.y = localCamPos.y; m_oldLocalCamera.z = localCamPos.z; } } m_cameraQuad = null; }
/* * 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(); } }