/// <summary> /// Checks the neighboring grid locations to see if there's an object that is too close to a certain point. /// </summary> /// <returns><c>true</c> if it is too close to something <c>false</c> otherwise.</returns> /// <param name="grid">Grid.</param> /// <param name="point">Point.</param> /// <param name="minDistance">Minimum distance.</param> /// <param name="cellSize">Cell size.</param> /// <param name="triangle">Triangle.</param> public bool overlappingPoint(Dictionary <long, ProceduralGenerationPoint> grid, ProceduralGenerationPoint point, float minDistance, float cellSize, int triangle) { Vector2 newPoint = point.uvPosition; long gridPoint = point.gridPosition; int y = (int)gridPoint / gridOffset; int x = (int)gridPoint - (y * gridOffset); int gridSpaces = Mathf.CeilToInt(minDistance / cellSize); long key; for (int i = x - gridSpaces; i < gridSpaces + x; ++i) { for (int j = y - gridSpaces; j < gridSpaces + y; ++j) { if (i != x && j != y) { key = i + j * gridOffset; if (grid.ContainsKey(key)) { if (inRange(grid[key].uvPosition, newPoint, minDistance + grid[key].size)) { return(true); } } } } } return(false); }
/// <summary> /// Gets the color at a location. /// </summary> /// <returns>The color at location on the me.</returns> /// <param name="point">Point.</param> public Color getColorAtTriangle(ProceduralGenerationPoint point) { int x = Mathf.FloorToInt(point.uvPosition.x * heatmapColors.width); int y = Mathf.FloorToInt(point.uvPosition.y * heatmapColors.height); return(heatmapColors.GetPixel(x, y)); }
/// <summary> /// Turns a Vector3 position on the mesh to a Vector2 uv point. /// </summary> /// <returns>The Vector2 uv point.</returns> /// <param name="point">Point.</param> public Vector2 meshPointToUv(ProceduralGenerationPoint point) { Vector3 toP1 = triangles[point.triangleIndex][0] - point.position; Vector3 toP2 = triangles[point.triangleIndex][1] - point.position; Vector3 toP3 = triangles[point.triangleIndex][2] - point.position; float triangleArea = Vector3.Cross(toP1 - toP2, toP1 - toP3).magnitude; float a1 = Vector3.Cross(toP2, toP3).magnitude / triangleArea; float a2 = Vector3.Cross(toP3, toP1).magnitude / triangleArea; float a3 = Vector3.Cross(toP1, toP2).magnitude / triangleArea; Vector2 uv = uvsToTriangles[point.triangleIndex][0] * a1 + uvsToTriangles[point.triangleIndex][1] * a2 + uvsToTriangles[point.triangleIndex][2] * a3; return(uv); }
/// <summary> /// Reconstructs the sample points after save file load. /// </summary> /// <param name="name">Name of planet.</param> public void reconstructSamplePoints(string name) { SystemLogger.write("Reconstructing sample points"); int i = 0; while (i < serializedSamplePointsByPlanet[name].samplePointLocations.Count) { long key = serializedSamplePointsByPlanet[name].samplePointKeys[i]; if (!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List <ProceduralGenerationPoint>()); } ProceduralGenerationPoint p = new ProceduralGenerationPoint(serializedSamplePointsByPlanet[name].samplePointLocations[i]); p.objectName = serializedSamplePointsByPlanet[name].samplePointObjects[i]; p.size = serializedSamplePointsByPlanet[name].samplePointSizes[i]; p.triangleIndex = serializedSamplePointsByPlanet[name].triangleIndexes[i]; samplePoints[key].Add(p); i++; } }
/// <summary> /// Generates the random point around an existing point. /// </summary> /// <returns>A point.</returns> /// <param name="triangleIndex">Triangle index.</param> /// <param name="triangles">Triangles.</param> /// <param name="uvsToTriangles">Uvs to triangles.</param> /// <param name="minDistance">Minimum distance.</param> public ProceduralGenerationPoint generateRandomPointAround(int triangleIndex, List <Vector3[]> triangles, List <Vector2[]> uvsToTriangles, float minDistance) { // the range of triangle index values away that a point can be generated int range = Mathf.CeilToInt(minDistance / triangleArea * 3f); // the actual index value away of the triangle used to generate a new point int x = 0; if (Random.Range(0, 2) == 0) { x = Random.Range(range, 2 * range); } else { x = Random.Range(-2 * range, -range); } while ((triangleIndex + x) >= triangles.Count || (triangleIndex + x) < 0) { if (Random.Range(0, 2) == 0) { x = Random.Range(range, 2 * range); } else { x = Random.Range(-2 * range, -range); } } ProceduralGenerationPoint p = new ProceduralGenerationPoint(getInterpolation(triangles [triangleIndex + x])); p.triangleIndex = triangleIndex + x; p.uvPosition = meshPointToUv(p); p.size = getSize(getColorChance(getColorAtTriangle(p))); p.c = getColorAtTriangle(p); return(p); }
/// <summary> /// Generates the poisson sampling points that can be used to determine where to place objects. /// </summary> /// <returns>The poisson sampling point.</returns> /// <param name="minDistance">Minimum distance.</param> /// <param name="newPointsCount">Number of new points that should be generated around an existing point.</param> public Dictionary <long, List <ProceduralGenerationPoint> > generatePoisson(float minDistance, int newPointsCount) { SystemLogger.write("Began generating poisson sample points"); // gets triangle indices from first submesh int[] triangleIndices = mesh.GetTriangles(0); Vector3[] vertices = mesh.vertices; Vector2[] uvs = mesh.uv; Vector3[] normals = mesh.normals; Dictionary <long, List <ProceduralGenerationPoint> > samplePoints = new Dictionary <long, List <ProceduralGenerationPoint> > (); List <ProceduralGenerationPoint> processList = new List <ProceduralGenerationPoint> (); ProceduralGenerationPoint point; int rand; long gridPoint; float minDis; int tries = 0; for (int i = 0; i < triangleIndices.Length - 2; i += 3) { Vector3[] triangleVertices = new Vector3[3]; triangleVertices[0] = vertices[triangleIndices[i]]; triangleVertices[1] = vertices[triangleIndices[i + 1]]; triangleVertices[2] = vertices[triangleIndices[i + 2]]; triangles.Add(triangleVertices); Vector2[] triangleUVs = new Vector2[3]; triangleUVs[0] = uvs[triangleIndices[i]]; triangleUVs[1] = uvs[triangleIndices[i + 1]]; triangleUVs[2] = uvs[triangleIndices[i + 2]]; uvsToTriangles.Add(triangleUVs); faceNormals.Add((normals[triangleIndices[i]] + normals[triangleIndices[i + 1]] + normals[triangleIndices[i + 2]]) / 3); } // calculates the ratio of a distance on the 3d mesh to a distance on the 2d uv by getting the distance from the same 2 points on both the mesh // and on the uv ProceduralGenerationPoint temp = new ProceduralGenerationPoint(getInterpolation(triangles [0])); temp.triangleIndex = 0; temp.uvPosition = meshPointToUv(temp); ProceduralGenerationPoint temp2 = new ProceduralGenerationPoint(getInterpolation(triangles [1])); temp2.triangleIndex = 1; temp2.uvPosition = meshPointToUv(temp2); uvToMeshRatio = Vector2.Distance(temp.uvPosition, temp2.uvPosition) / Vector3.Distance(temp.position, temp2.position); // size of cells in the mesh grid for generation cellSize = (minDistance / Mathf.Sqrt(2f)) * uvToMeshRatio; // calculates the area of a triangle on the mesh Vector3 side1 = triangles [0] [0] - triangles [0] [1]; Vector3 side2 = triangles [0] [1] - triangles [0] [2]; Vector3 side3 = triangles [0] [2] - triangles [0] [0]; triangleArea = Vector3.Cross(side1 - side2, side1 - side3).magnitude; // the number to offset the y value from the x to create a unique index for vector2 hashes in the dictionary int initialNumber = Mathf.CeilToInt((triangleArea * uvToMeshRatio) / cellSize) * triangles.Count; int power = Mathf.CeilToInt(Mathf.Log10(initialNumber)); gridOffset = Mathf.RoundToInt(Mathf.Pow(10, power)); power = Mathf.CeilToInt(Mathf.Log10(planetSections)); chunkGridOffset = Mathf.RoundToInt(Mathf.Pow(10, power)); SystemLogger.write("Creating starting seeds..."); // creates the starting seeds from which points will be generated around for (int i = 0; i < startingSeeds; ++i) { rand = Random.Range(0, triangles.Count); ProceduralGenerationPoint firstPoint = new ProceduralGenerationPoint(getInterpolation(triangles [rand])); firstPoint.triangleIndex = rand; firstPoint.uvPosition = meshPointToUv(firstPoint); // the color at that location Color c = getColorAtTriangle(firstPoint); firstPoint.size = getSize(getColorChance(c)); firstPoint.c = c; gridPoint = toGrid(firstPoint.uvPosition, chunkCellSize, chunkGridOffset); firstPoint.chunkGridPosition = gridPoint; firstPoint.gridPosition = toGrid(firstPoint.uvPosition, cellSize, gridOffset); // the minimum distance of generation taking into acount the minimum distance allowed between objects, the density of the region, and the size of // the object being generated around, all multiplied by the uvToMeshRatio so that the measurement is given in terms of uv distance minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio; tries = 0; // if there is already a point within that cell then it is automatically too close to another point // otherwise it will check with overlappingPoint whether or not it is too close to any cells in its neighborhood // if either are true then that means the point is invalid and another point is generated as an attemp while ((1 - getDensity(firstPoint.c)) < startingSeedsDensityThreshold || chunkGrid.ContainsKey(gridPoint) || grid.ContainsKey(firstPoint.gridPosition) || overlappingPoint(grid, firstPoint, minDis, cellSize, firstPoint.triangleIndex)) { rand = Random.Range(0, triangles.Count); firstPoint.position = getInterpolation(triangles [rand]); firstPoint.triangleIndex = rand; firstPoint.uvPosition = meshPointToUv(firstPoint); gridPoint = toGrid(firstPoint.uvPosition, chunkCellSize, chunkGridOffset); firstPoint.chunkGridPosition = gridPoint; firstPoint.gridPosition = toGrid(firstPoint.uvPosition, cellSize, gridOffset); minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio; // it will only keep generating new points in an attempt at generating a valid point as many times as the maxAttempts allows if (tries < maxAttempts) { tries++; } else { break; } } // tries < maxAttempts that means it exited the while loop because there was a valid point and not because there were too many // atempts taken if (tries < maxAttempts) { // uses grid location as key in sample points dictionary for access later long key = firstPoint.chunkGridPosition; firstPoint.gridPosition = toGrid(firstPoint.uvPosition, cellSize, gridOffset); if (!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List <ProceduralGenerationPoint>()); } // registers a chunk to mark it as having objects if chunk is not already registered if (!chunkStatus.ContainsKey(key)) { chunkStatus.Add(key, false); } if (!chunkGrid.ContainsKey(key)) { chunkGrid.Add(key, new List <EnvironmentOrienter>()); } samplePoints[key].Add(firstPoint); processList.Add(firstPoint); // add point to grid grid.Add(firstPoint.gridPosition, firstPoint); } } currentObjects = startingSeeds; // not based on those seeds, generate objects around them SystemLogger.write("Creating the surrounding points...."); while (currentObjects < maxObjects && processList.Count != 0) { point = processList[processList.Count - 1]; processList.RemoveAt(processList.Count - 1); tries = 0; for (int i = 0; i < newPointsCount; ++i) { // generate a random point around an existing point ProceduralGenerationPoint newPoint = generateRandomPointAround(point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large); Color c = getColorAtTriangle(newPoint); newPoint.size = getSize(getColorChance(c)); newPoint.c = c; gridPoint = toGrid(newPoint.uvPosition, cellSize, gridOffset); newPoint.gridPosition = gridPoint; minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio; while ((1 - getDensity(newPoint.c)) < generationDensityThreshold || grid.ContainsKey(gridPoint) || overlappingPoint(grid, newPoint, minDis, cellSize, newPoint.triangleIndex)) { newPoint = generateRandomPointAround(point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large); minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio; gridPoint = toGrid(newPoint.uvPosition, cellSize, gridOffset); newPoint.gridPosition = gridPoint; if (tries < maxAttempts) { tries++; } else { break; } } if (tries < maxAttempts) { long key = toGrid(newPoint.uvPosition, chunkCellSize, chunkGridOffset); if (!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List <ProceduralGenerationPoint>()); } samplePoints[key].Add(newPoint); processList.Add(newPoint); if (!chunkStatus.ContainsKey(key)) { chunkStatus.Add(key, false); } if (!chunkGrid.ContainsKey(key)) { chunkGrid.Add(key, new List <EnvironmentOrienter>()); } currentObjects++; grid.Add(gridPoint, newPoint); newPoint.chunkGridPosition = key; tries = 0; } else { break; } if (currentObjects >= maxObjects) { break; } } } return(samplePoints); }
/// <summary> /// Reconstructs the sample points after save file load. /// </summary> /// <param name="name">Name of planet.</param> public void reconstructSamplePoints(string name) { SystemLogger.write ("Reconstructing sample points"); int i = 0; while(i < serializedSamplePointsByPlanet[name].samplePointLocations.Count) { long key = serializedSamplePointsByPlanet[name].samplePointKeys[i]; if(!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List<ProceduralGenerationPoint>()); } ProceduralGenerationPoint p = new ProceduralGenerationPoint(serializedSamplePointsByPlanet[name].samplePointLocations[i]); p.objectName = serializedSamplePointsByPlanet[name].samplePointObjects[i]; p.size = serializedSamplePointsByPlanet[name].samplePointSizes[i]; p.triangleIndex = serializedSamplePointsByPlanet[name].triangleIndexes[i]; samplePoints[key].Add (p); i++; } }
/// <summary> /// Checks the neighboring grid locations to see if there's an object that is too close to a certain point. /// </summary> /// <returns><c>true</c> if it is too close to something <c>false</c> otherwise.</returns> /// <param name="grid">Grid.</param> /// <param name="point">Point.</param> /// <param name="minDistance">Minimum distance.</param> /// <param name="cellSize">Cell size.</param> /// <param name="triangle">Triangle.</param> public bool overlappingPoint(Dictionary<long, ProceduralGenerationPoint> grid, ProceduralGenerationPoint point, float minDistance, float cellSize, int triangle) { Vector2 newPoint = point.uvPosition; long gridPoint = point.gridPosition; int y = (int) gridPoint / gridOffset; int x = (int) gridPoint - (y * gridOffset); int gridSpaces = Mathf.CeilToInt(minDistance / cellSize); long key; for(int i = x - gridSpaces; i < gridSpaces + x; ++i) { for(int j = y - gridSpaces; j < gridSpaces + y; ++j) { if( i != x && j != y) { key = i + j * gridOffset; if(grid.ContainsKey(key)) { if(inRange(grid[key].uvPosition, newPoint, minDistance + grid[key].size)) { return true; } } } } } return false; }
/// <summary> /// Turns a Vector3 position on the mesh to a Vector2 uv point. /// </summary> /// <returns>The Vector2 uv point.</returns> /// <param name="point">Point.</param> public Vector2 meshPointToUv(ProceduralGenerationPoint point) { Vector3 toP1 = triangles[point.triangleIndex][0] - point.position; Vector3 toP2 = triangles[point.triangleIndex][1] - point.position; Vector3 toP3 = triangles[point.triangleIndex][2] - point.position; float triangleArea = Vector3.Cross (toP1 - toP2, toP1 - toP3).magnitude; float a1 = Vector3.Cross (toP2, toP3).magnitude / triangleArea; float a2 = Vector3.Cross (toP3, toP1).magnitude / triangleArea; float a3 = Vector3.Cross (toP1, toP2).magnitude / triangleArea; Vector2 uv = uvsToTriangles[point.triangleIndex][0] * a1 + uvsToTriangles[point.triangleIndex][1] * a2 + uvsToTriangles[point.triangleIndex][2] * a3; return uv; }
/// <summary> /// Gets the color at a location. /// </summary> /// <returns>The color at location on the me.</returns> /// <param name="point">Point.</param> public Color getColorAtTriangle(ProceduralGenerationPoint point) { int x = Mathf.FloorToInt(point.uvPosition.x * heatmapColors.width); int y = Mathf.FloorToInt(point.uvPosition.y * heatmapColors.height); return heatmapColors.GetPixel(x, y); }
/// <summary> /// Generates the random point around an existing point. /// </summary> /// <returns>A point.</returns> /// <param name="triangleIndex">Triangle index.</param> /// <param name="triangles">Triangles.</param> /// <param name="uvsToTriangles">Uvs to triangles.</param> /// <param name="minDistance">Minimum distance.</param> public ProceduralGenerationPoint generateRandomPointAround(int triangleIndex, List<Vector3[]> triangles, List<Vector2[]> uvsToTriangles, float minDistance) { // the range of triangle index values away that a point can be generated int range = Mathf.CeilToInt (minDistance / triangleArea * 3f); // the actual index value away of the triangle used to generate a new point int x = 0; if (Random.Range (0, 2) == 0) { x = Random.Range (range, 2*range); } else { x = Random.Range (-2 * range, -range); } while((triangleIndex + x) >= triangles.Count || (triangleIndex + x) < 0) { if (Random.Range (0, 2) == 0) { x = Random.Range (range, 2*range); } else { x = Random.Range (-2 * range, -range); } } ProceduralGenerationPoint p = new ProceduralGenerationPoint(getInterpolation (triangles [triangleIndex + x])); p.triangleIndex = triangleIndex + x; p.uvPosition = meshPointToUv (p); p.size = getSize(getColorChance(getColorAtTriangle(p))); p.c = getColorAtTriangle (p); return p; }
/// <summary> /// Generates the poisson sampling points that can be used to determine where to place objects. /// </summary> /// <returns>The poisson sampling point.</returns> /// <param name="minDistance">Minimum distance.</param> /// <param name="newPointsCount">Number of new points that should be generated around an existing point.</param> public Dictionary<long, List<ProceduralGenerationPoint>> generatePoisson(float minDistance, int newPointsCount) { SystemLogger.write ("Began generating poisson sample points"); // gets triangle indices from first submesh int[] triangleIndices = mesh.GetTriangles (0); Vector3[] vertices = mesh.vertices; Vector2[] uvs = mesh.uv; Vector3[] normals = mesh.normals; Dictionary<long, List<ProceduralGenerationPoint>> samplePoints = new Dictionary<long, List<ProceduralGenerationPoint>> (); List<ProceduralGenerationPoint> processList = new List<ProceduralGenerationPoint> (); ProceduralGenerationPoint point; int rand; long gridPoint; float minDis; int tries = 0; for(int i = 0; i < triangleIndices.Length - 2; i+=3) { Vector3[] triangleVertices = new Vector3[3]; triangleVertices[0] = vertices[triangleIndices[i]]; triangleVertices[1] = vertices[triangleIndices[i+1]]; triangleVertices[2] = vertices[triangleIndices[i+2]]; triangles.Add (triangleVertices); Vector2[] triangleUVs = new Vector2[3]; triangleUVs[0] = uvs[triangleIndices[i]]; triangleUVs[1] = uvs[triangleIndices[i + 1]]; triangleUVs[2] = uvs[triangleIndices[i + 2]]; uvsToTriangles.Add(triangleUVs); faceNormals.Add ((normals[triangleIndices[i]] + normals[triangleIndices[i + 1]] + normals[triangleIndices[i + 2]])/3); } // calculates the ratio of a distance on the 3d mesh to a distance on the 2d uv by getting the distance from the same 2 points on both the mesh // and on the uv ProceduralGenerationPoint temp = new ProceduralGenerationPoint (getInterpolation (triangles [0])); temp.triangleIndex = 0; temp.uvPosition = meshPointToUv (temp); ProceduralGenerationPoint temp2 = new ProceduralGenerationPoint (getInterpolation (triangles [1])); temp2.triangleIndex = 1; temp2.uvPosition = meshPointToUv (temp2); uvToMeshRatio = Vector2.Distance (temp.uvPosition, temp2.uvPosition) / Vector3.Distance (temp.position, temp2.position); // size of cells in the mesh grid for generation cellSize = (minDistance / Mathf.Sqrt (2f)) * uvToMeshRatio; // calculates the area of a triangle on the mesh Vector3 side1 = triangles [0] [0] - triangles [0] [1]; Vector3 side2 = triangles [0] [1] - triangles [0] [2]; Vector3 side3 = triangles [0] [2] - triangles [0] [0]; triangleArea = Vector3.Cross (side1 - side2, side1 - side3).magnitude; // the number to offset the y value from the x to create a unique index for vector2 hashes in the dictionary int initialNumber = Mathf.CeilToInt ((triangleArea * uvToMeshRatio) / cellSize) * triangles.Count; int power = Mathf.CeilToInt (Mathf.Log10 (initialNumber)); gridOffset = Mathf.RoundToInt(Mathf.Pow (10, power)); power = Mathf.CeilToInt (Mathf.Log10(planetSections)); chunkGridOffset = Mathf.RoundToInt (Mathf.Pow (10, power)); SystemLogger.write ("Creating starting seeds..."); // creates the starting seeds from which points will be generated around for (int i = 0; i < startingSeeds; ++i) { rand = Random.Range (0, triangles.Count); ProceduralGenerationPoint firstPoint = new ProceduralGenerationPoint (getInterpolation (triangles [rand])); firstPoint.triangleIndex = rand; firstPoint.uvPosition = meshPointToUv(firstPoint); // the color at that location Color c = getColorAtTriangle(firstPoint); firstPoint.size = getSize(getColorChance(c)); firstPoint.c = c; gridPoint = toGrid (firstPoint.uvPosition, chunkCellSize, chunkGridOffset); firstPoint.chunkGridPosition = gridPoint; firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset); // the minimum distance of generation taking into acount the minimum distance allowed between objects, the density of the region, and the size of // the object being generated around, all multiplied by the uvToMeshRatio so that the measurement is given in terms of uv distance minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio; tries = 0; // if there is already a point within that cell then it is automatically too close to another point // otherwise it will check with overlappingPoint whether or not it is too close to any cells in its neighborhood // if either are true then that means the point is invalid and another point is generated as an attemp while ((1- getDensity(firstPoint.c)) < startingSeedsDensityThreshold || chunkGrid.ContainsKey(gridPoint) || grid.ContainsKey(firstPoint.gridPosition)|| overlappingPoint(grid, firstPoint, minDis, cellSize, firstPoint.triangleIndex)) { rand = Random.Range (0, triangles.Count); firstPoint.position = getInterpolation (triangles [rand]); firstPoint.triangleIndex = rand; firstPoint.uvPosition = meshPointToUv(firstPoint); gridPoint = toGrid(firstPoint.uvPosition, chunkCellSize, chunkGridOffset); firstPoint.chunkGridPosition = gridPoint; firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset); minDis = (minDistance + distanceVariance * getDensity(c) + firstPoint.size) * uvToMeshRatio; // it will only keep generating new points in an attempt at generating a valid point as many times as the maxAttempts allows if(tries < maxAttempts) { tries ++; } else { break; } } // tries < maxAttempts that means it exited the while loop because there was a valid point and not because there were too many // atempts taken if (tries < maxAttempts) { // uses grid location as key in sample points dictionary for access later long key = firstPoint.chunkGridPosition; firstPoint.gridPosition = toGrid (firstPoint.uvPosition, cellSize, gridOffset); if(!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List<ProceduralGenerationPoint>()); } // registers a chunk to mark it as having objects if chunk is not already registered if(!chunkStatus.ContainsKey(key)) { chunkStatus.Add(key, false); } if(!chunkGrid.ContainsKey(key)) { chunkGrid.Add(key, new List<EnvironmentOrienter>()); } samplePoints[key].Add (firstPoint); processList.Add (firstPoint); // add point to grid grid.Add (firstPoint.gridPosition, firstPoint); } } currentObjects = startingSeeds; // not based on those seeds, generate objects around them SystemLogger.write ("Creating the surrounding points...."); while (currentObjects < maxObjects && processList.Count != 0) { point = processList[processList.Count - 1]; processList.RemoveAt(processList.Count - 1); tries = 0; for(int i = 0; i < newPointsCount; ++i) { // generate a random point around an existing point ProceduralGenerationPoint newPoint = generateRandomPointAround (point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large); Color c = getColorAtTriangle(newPoint); newPoint.size = getSize(getColorChance(c)); newPoint.c = c; gridPoint = toGrid (newPoint.uvPosition, cellSize, gridOffset); newPoint.gridPosition = gridPoint; minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio; while ((1- getDensity(newPoint.c)) < generationDensityThreshold || grid.ContainsKey(gridPoint) || overlappingPoint(grid, newPoint, minDis,cellSize, newPoint.triangleIndex)) { newPoint = generateRandomPointAround (point.triangleIndex, triangles, uvsToTriangles, minDistance + distanceVariance + large); minDis = (minDistance + distanceVariance * getDensity(c) + newPoint.size) * uvToMeshRatio; gridPoint = toGrid (newPoint.uvPosition, cellSize, gridOffset); newPoint.gridPosition = gridPoint; if(tries < maxAttempts) { tries ++; } else { break; } } if (tries < maxAttempts) { long key = toGrid(newPoint.uvPosition, chunkCellSize, chunkGridOffset); if(!samplePoints.ContainsKey(key)) { samplePoints.Add(key, new List<ProceduralGenerationPoint>()); } samplePoints[key].Add (newPoint); processList.Add(newPoint); if(!chunkStatus.ContainsKey(key)) { chunkStatus.Add(key, false); } if(!chunkGrid.ContainsKey(key)) { chunkGrid.Add(key, new List<EnvironmentOrienter>()); } currentObjects++; grid.Add(gridPoint, newPoint); newPoint.chunkGridPosition = key; tries = 0; } else { break; } if(currentObjects >= maxObjects) { break; } } } return samplePoints; }