/** * Get all the instances withing the given radius of the provided location. * * @param subdivision * If we should get the instance count for subdivisions (grass) or for big cells. */ public int GetInstanceCountLocation(Vector3 position, float radius, bool subdivision) { int count = 0; Vector3 min = position - new Vector3(radius, radius, radius); Vector3 max = position + new Vector3(radius, radius, radius); float distanceDelta = radius * radius; float x, y, z; // Iterate divisions FoliageCell.IterateMinMax(min, max, false, (int hash) => { FoliageCellData cell; if (m_FoliageData.TryGetValue(hash, out cell) == false) { return; } if (subdivision == false) { // Count all the tree foliage that overlaps the sphere foreach (var data in cell.m_TypeHashLocationsEditor.Values) { foreach (var instances in data.Values) { for (int i = 0; i < instances.Count; i++) { x = instances[i].m_Position.x - position.x; y = instances[i].m_Position.y - position.y; z = instances[i].m_Position.z - position.z; if ((x * x + y * y + z * z) < distanceDelta) { count++; } } } } } else { // Iterate subdivisions Vector3 minLocal = GetLocalInCell(min, cell); Vector3 maxLocal = GetLocalInCell(max, cell); FoliageCell.IterateMinMax(minLocal, maxLocal, true, (int hashLocal) => { FoliageCellSubdividedData cellSubdivided; if (cell.m_FoliageDataSubdivided.TryGetValue(hashLocal, out cellSubdivided) == false) { return; } // Count all the grass foliage that overlaps the sphere foreach (var data in cellSubdivided.m_TypeHashLocationsEditor.Values) { foreach (var instances in data.Values) { for (int i = 0; i < instances.Count; i++) { x = instances[i].m_Position.x - position.x; y = instances[i].m_Position.y - position.y; z = instances[i].m_Position.z - position.z; if ((x * x + y * y + z * z) < distanceDelta) { count++; } } } } }); } }); return(count); }
/** * Removes foliage instances. * * @return True if we removed anything */ public bool RemoveInstances(int typeHash, Vector3 position, float radius = 0.3f /*30cm default position delta */) { Vector3 min = position - new Vector3(radius, radius, radius); Vector3 max = position + new Vector3(radius, radius, radius); bool anyRemoved = false; bool anyGrassRemoved = false; float x, y, z; float distanceDelta = radius * radius; // Remove all the foliage that overlaps the sphere FoliageCell.IterateMinMax(min, max, false, (int hash) => { if (m_FoliageData.ContainsKey(hash) == false) { return; } FoliageCellData cell = m_FoliageData[hash]; // Remove the types from the cell if (cell.m_TypeHashLocationsEditor.ContainsKey(typeHash)) { var labeledData = cell.m_TypeHashLocationsEditor[typeHash]; foreach (var instances in labeledData.Values) { for (int i = instances.Count - 1; i >= 0; i--) { x = instances[i].m_Position.x - position.x; y = instances[i].m_Position.y - position.y; z = instances[i].m_Position.z - position.z; // If we are at a distance smaller than the threshold then remove the instance if ((x * x + y * y + z * z) < distanceDelta) { instances.RemoveAt(i); // We removed from the cell, we have to recalculate the extended bounds anyRemoved = true; } } } } // Remove the types from the subdivided cells // Iterate subdivisions Vector3 minLocal = GetLocalInCell(min, cell); Vector3 maxLocal = GetLocalInCell(max, cell); FoliageCell.IterateMinMax(minLocal, maxLocal, true, (int hashLocal) => { FoliageCellSubdividedData cellSubdivided; if (cell.m_FoliageDataSubdivided.TryGetValue(hashLocal, out cellSubdivided) == false) { return; } // Count all the grass foliage that overlaps the sphere if (cellSubdivided.m_TypeHashLocationsEditor.ContainsKey(typeHash)) { var data = cellSubdivided.m_TypeHashLocationsEditor[typeHash]; foreach (var instances in data.Values) { for (int i = instances.Count - 1; i >= 0; i--) { x = instances[i].m_Position.x - position.x; y = instances[i].m_Position.y - position.y; z = instances[i].m_Position.z - position.z; // If we are at a distance smaller than the threshold then remove the instance if ((x * x + y * y + z * z) < distanceDelta) { instances.RemoveAt(i); // Just for grass removal... anyGrassRemoved = true; } } } } RemoveEmptyTypeDataCellSubdivided(cellSubdivided); if (IsSubCellEmpty(cellSubdivided)) { cell.m_FoliageDataSubdivided.Remove(hashLocal); } }); // If we removed everything from a cell then clear it from the list completely RemoveEmptyTypeDataCell(cell); if (IsCellEmpty(cell)) { m_FoliageData.Remove(hash); } }); if (anyRemoved) { RecalculateBoundsAfterRemove(); } return(anyRemoved || anyGrassRemoved); }