public void PopulateCluster(Vector3 position, Rect boundary, float minScale, float maxScale, float density, float resolution) { // Empty the cluster if (positionList == null) { positionList = new List <Vector3>(); } else { positionList.Clear(); } if (scaleList == null) { scaleList = new List <Vector3>(); } else { scaleList.Clear(); } Vector3 origin = new Vector3(position.x - (boundary.width / 2f), position.y, position.z - (boundary.height / 2f)); float noiseOffset = UnityEngine.Random.Range(0f, boundary.width); Vector2 noiseCoords = Vector2.zero; float clusterNoiseTileSize = boundary.width / 5f; // Convert values from float to int to avoid a float for(;;) loop int resolutionInt = Mathf.FloorToInt(resolution * 1000f); int widthInt = Mathf.FloorToInt(boundary.width * 1000); int lengthInt = Mathf.FloorToInt(boundary.height * 1000); float xF = 0f, zF = 0f; for (int x = 0; x < widthInt; x += resolutionInt) { for (int z = 0; z < lengthInt; z += resolutionInt) { // Convert back to floats xF = x / 1000f; zF = z / 1000f; // Get a perlin noise value for this point in the cluster noiseCoords.x = xF + noiseOffset; noiseCoords.y = zF + noiseOffset; float noiseValue = Mathf.Abs(LBNoise.PerlinFractalNoise(noiseCoords.x / clusterNoiseTileSize, noiseCoords.y / clusterNoiseTileSize, 5) - 0.5f) * 4f; // If the noise value is less than density don't create the position if (noiseValue < density) { positionList.Add(new Vector3(origin.x + xF, origin.y, origin.z + zF)); scaleList.Add(Vector3.one * UnityEngine.Random.Range(minScale, maxScale)); } } } }
/// <summary> /// Find a random offset (position) within an area with the given radius for a GroupMember. /// USAGE: Vector2 offset = LBGroupMember.GetRandomOffset(lbGroupMember, basePlaneWidth / 2f, 100); /// </summary> /// <param name="lbGroupMember"></param> /// <param name="radius"></param> /// <param name="maxAttempts"></param> /// <returns></returns> public static Vector2 GetRandomOffset(LBGroupMember lbGroupMember, float radius, int maxAttempts) { Vector2 offset = Vector2.zero; Vector2 noiseCoords = Vector2.zero; // Declare and initialise variables // To start with we have made zero attempts and not found a legal placement // (by this we mean a placement within the circle, and following some extra rules like noise) bool foundLegalPlacement = false; int attempts = 0; // Repeat until we find a legal placement or we try maxAttempts times while (!foundLegalPlacement && attempts < maxAttempts) { // Generate a random position - the chance of this placement not being legal // is (4 - PI) / 4 = 21.5% (so chance of it being legal is 78.5%) // Thus it is 99% likely that within 3 attempts we will have found a correct placement offset.x = UnityEngine.Random.Range(-radius, radius); offset.y = UnityEngine.Random.Range(-radius, radius); // Judge legality: First, based on whether placement is within radius... foundLegalPlacement = offset.magnitude < radius; if (foundLegalPlacement && lbGroupMember != null && lbGroupMember.useNoise) { // ... then by whether it follows noise rules noiseCoords.x = offset.x + lbGroupMember.noiseOffset; noiseCoords.y = offset.y + lbGroupMember.noiseOffset; float noiseValue = Mathf.Abs(LBNoise.PerlinFractalNoise(noiseCoords.x / lbGroupMember.noiseTileSize, noiseCoords.y / lbGroupMember.noiseTileSize, 5) - 0.5f) * 4f; // If the noise value is less than (1 - prefab cutoff value) placement is not legal foundLegalPlacement = noiseValue >= 1f - lbGroupMember.noisePlacementCutoff; } attempts++; } // If we have tried maxAttempts times and still not found a correct placement, just set the position to the centre if (!foundLegalPlacement) { offset = Vector2.zero; } return(offset); }