I am trying to use Perlin noise as a pattern for generating forests / clusters of 2D prefabs in unity, for my procedurally generated game. So my plan was to generate Perlin noise, and then use the dark tones of the perlin noise to generate forest-looking clusters of game objects. The noise i generated, and has an offsetX and offsetY value, which is a random number between 0 and 999999, to randomly offset the noise generated, within the frame. The noise is being displayed in a quad, but when its finished i will only use the GameObjects alone, and not the noise under them. Right now i only have the noise visible, so that I can see the correlation between the spawn-points and the noise. So the problem is that right now, it technically works, but the GameObjects are generated based on the noise in the frame at the offsetX 0, and offsetY 0, however the noise is random every time, but not the generated gameobjects, so for some reason, the RandomObjectSpawner script doesent use the offsetX and offsetY values, to calculate which tells it which "frame" of noise it is, (e.g.) at offsetX 28904, offsetY 98201 noise seed, it would still just generate the points in the pattern of the offset 0 noise position. Example screenshots will be provided.
Here is the image of the Noise and Generated GameObjects, at offsetX 0 and offsetY 0
and here it is when the offsetX and offsetY values are random: So as you can see on picture 2, the little placeholder test-plants spawn in pretty much the same pattern as in the first image. So i need them to always spawn at the pattern of the offsetX and offsetY values that are randomly generated.
The following is my code for generating the Perlin noise: `public class PerlinNoise : MonoBehaviour { // Texture dimensions public int width = 256; public int height = 256;
// Scale and offset parameters for controlling Perlin noise
public float scale = 20f;
public float offsetX = 0f;
public float offsetY = 0f;
void Start()
{
// Randomize the offsets to create different noise patterns
offsetX = Random.Range(0f, 999999f);
offsetY = Random.Range(0f, 999999f);
}
void Update()
{
// Get the renderer component of the attached GameObject
Renderer renderer = GetComponent<Renderer>();
// Apply the generated texture to the object's material
renderer.material.mainTexture = GenerateTexture();
}
// Make the GenerateTexture method public
public Texture2D GenerateTexture()
{
// Create a new 2D texture with specified dimensions
Texture2D texture = new Texture2D(width, height);
// Generate a Perlin noise map for the texture
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
// Calculate the color for the current pixel using Perlin noise
Color color = CalculateColor(x, y);
// Set the pixel's color in the texture
texture.SetPixel(x, y, color);
}
}
// Apply changes to the texture
texture.Apply();
return texture;
}
Color CalculateColor(int x, int y)
{
// Calculate the normalized coordinates within the texture
float xCoord = (float)x / width * scale + offsetX;
float yCoord = (float)y / height * scale + offsetY;
// Generate a Perlin noise value at the given coordinates
float sample = Mathf.PerlinNoise(xCoord, yCoord);
// Create a grayscale color using the Perlin noise value
return new Color(sample, sample, sample);
}
}`
And this is my code for spawning in the Game-Objects: `public class RandomObjectSpawner : MonoBehaviour { // The prefab to instantiate on dark tones public GameObject prefabToInstantiate;
// Reference to the PerlinNoise script
public PerlinNoise perlinNoiseScript;
// Threshold to determine dark tones
public float threshold = 0.4f;
// Number of objects to spawn
public int numberOfObjects = 10;
void Start() {
// Ensure that the PerlinNoise script is assigned in the Inspector
if (perlinNoiseScript == null) {
Debug.LogError("PerlinNoise script is not assigned.");
return;
}
// Get the offsetX and offsetY values from the PerlinNoise script
float offsetX = perlinNoiseScript.offsetX;
float offsetY = perlinNoiseScript.offsetY;
// Generate the Perlin noise texture
Texture2D noiseTexture = perlinNoiseScript.GenerateTexture();
// Calculate the width and height of the generated texture
int width = noiseTexture.width;
int height = noiseTexture.height;
// Create a list to store available spawn positions
List<Vector2Int> availableSpawnPositions = new List<Vector2Int>();
// Loop through the pixels of the Perlin noise texture, starting from offsetX and offsetY
for (int x = (int)perlinNoiseScript.offsetX; x < width; x++) {
for (int y = (int)perlinNoiseScript.offsetY; y < height; y++) {
// Get the color at the current pixel
Color color = noiseTexture.GetPixel(x, y);
// Check if the grayscale value is below the threshold
if (color.grayscale <= threshold) {
// Add the position to the list of available spawn positions
availableSpawnPositions.Add(new Vector2Int(x, y));
}
}
}
// Shuffle the list of available spawn positions for randomness
ShuffleList(availableSpawnPositions);
// Spawn the specified number of objects randomly from the shuffled list
int spawnedObjectCount = 0;
foreach (Vector2Int spawnPosition in availableSpawnPositions) {
if (spawnedObjectCount >= numberOfObjects)
break;
// Calculate the world position for the object based on texture coordinates
float worldX = (spawnPosition.x - (int)perlinNoiseScript.offsetX) * perlinNoiseScript.transform.localScale.x / width + perlinNoiseScript.transform.position.x - (perlinNoiseScript.transform.localScale.x / 2.0f);
float worldY = (spawnPosition.y - (int)perlinNoiseScript.offsetY) * perlinNoiseScript.transform.localScale.y / height + perlinNoiseScript.transform.position.y - (perlinNoiseScript.transform.localScale.y / 2.0f);
float worldZ = perlinNoiseScript.transform.position.z;
// Spawn the object at the calculated position
Instantiate(prefabToInstantiate, new Vector3(worldX, worldY, worldZ), Quaternion.identity);
spawnedObjectCount++;
}
}
// Function to shuffle a list
void ShuffleList<T>(List<T> list) {
int n = list.Count;
while (n > 1) {
n--;
int k = Random.Range(0, n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}`
Thanks in advance. :)
Now that you've fixed the order of execution, randomising the values in Awake, I believe the second error is in the for loop here which is why you're not seeing anything.
// Loop through the pixels of the Perlin noise texture, starting from offsetX and offsetY
for (int x = (int)perlinNoiseScript.offsetX; x < width; x++) {
for (int y = (int)perlinNoiseScript.offsetY; y < height; y++)
It should simply be...
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++)
As you're sampling from the texture to get the values, that will start from 0. Good luck with the project. :)