tim_weaver
tim_weaver

Reputation: 21

Random rotation and scale on procedural created objects

I am trying to make a procedural city generate but all of the buildings in the same group are facing the same direction (rotated the same) and are the same scale. I am trying to add variation in height and rotation so it looks more random. This is what I have so far but maybe I am going about this all the wrong way. I am new to programming so I appreciate any help you guys could give. Thank you!

public GameObject[] buildings;
public int mapWidth = 20;
public int mapHeight = 20;
int buildingFootprint = 45;
float randomY = Random.Range(-360f, 360f);


// Procedural Generation
void Start ()
{
    float seed = Random.Range(0, 500);
    for (int h = 0; h < mapHeight; h++)
    {
        for (int w = 0; w < mapWidth; w++)
        {
            int result = (int)(Mathf.PerlinNoise(w/3.0f + seed, h/3.0f + seed) * 50);
            Vector3 pos = new Vector3(w * buildingFootprint, 10, h * buildingFootprint);
            Vector3 rot = new Vector3(0, randomY, 0);

            if (result < 5)
                Instantiate(buildings[0], pos, Quaternion.Euler(rot));
            else if (result < 10)
                Instantiate(buildings[5], pos, Quaternion.Euler(rot));
            else if (result < 15)
                Instantiate(buildings[6], pos, Quaternion.Euler(rot));
            else if (result < 20)
                Instantiate(buildings[1], pos, Quaternion.Euler(rot));
            else if (result < 30)
                Instantiate(buildings[2], pos, Quaternion.Euler(rot));
            else if (result < 40)
                Instantiate(buildings[3], pos, Quaternion.Euler(rot));
            else if (result < 50)
                Instantiate(buildings[4], pos, Quaternion.Euler(rot));
        }
    }

}

Upvotes: 0

Views: 1012

Answers (1)

Fiffe
Fiffe

Reputation: 1256

It's because you set their rotation to Quaternion.identity

The identity rotation (Read Only).

This quaternion corresponds to "no rotation" - the object is perfectly aligned with the world or parent axes.

Set it to random rotation like this (I'm assuming you want to rotate them on Y axis):

// getting random rotation
float randomY = Random.Range(-360f, 360f); 

// assigning random rotation to Y axis
Vector3 rot = new Vector3(0, randomY, 0); 

// instantiating random building on position `pos` and rotation `rot`, I used `Quaternion.Euler` to convert the Vector3 to Quaternion
Instantiate(buildings[index], pos, Quaternion.Euler(rot)); 

For scaling you need to decide if you want to scale them uniformly or you want to have random scale on every axis. It would look something like this:

// getting random scale
Vector3 scale = Vector3.one;
if(scaleUniform)
{
    float randomScale = Random.Range(min, max);

    scale = new Vector3(randomScale, randomScale, randomScale);
}
else
{
    scale = new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(min, max));
}

// instantiating random building on position `pos` and rotation `rot`, I used `Quaternion.Euler` to convert the Vector3 to Quaternion
GameObject building = Instantiate(buildings[index], pos, Quaternion.Euler(rot)); 

// set the scale
building.localScale = scale;

Ultimately you should end up with a code like this:

public GameObject[] buildings;
public int mapWidth = 20;
public int mapHeight = 20;
int buildingFootprint = 45;
bool scaleUniform = true;


// Procedural Generation
void Start ()
{
    float seed = Random.Range(0, 500);
    for (int h = 0; h < mapHeight; h++)
    {
        for (int w = 0; w < mapWidth; w++)
        {
            int result = (int)(Mathf.PerlinNoise(w/3.0f + seed, h/3.0f + seed) * 50);
            float randomY = Random.Range(-360f, 360f); // get random rotation for Y axis

            Vector3 pos = new Vector3(w * buildingFootprint, 10, h * buildingFootprint);
            Vector3 rot = new Vector3(0, randomY, 0); // set the random Y rotation to a new Vector3
            Vector3 scale = Vector3.one; // create a new Vector3 for scale

            if(scaleUniform) // scale the object uniformly
            {
                float randomScale = Random.Range(min, max);

                scale = new Vector3(randomScale, randomScale, randomScale);
            }
            else // or scale it randomly on every axis
            {
                scale = new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(min, max));
            }

            int index = 0; // declare index here so you dont repeat yourself in ifs

            if (result < 5) // now you only set index value instead of copying and pasting long code in each if else
                index = 0;
            else if (result < 10)
                index = 5;
            else if (result < 15)
                index = 6;
            else if (result < 20)
                index = 1;
            else if (result < 30)
                index = 2;
            else if (result < 40)
                index = 3;
            else if (result < 50)
                index = 4;

            GameObject spawnedBuilding = Instantiate(buildings[index], pos, Quaternion.Euler(rot)); // and finally instantiate the object
            spawnedBuilding.transform.localScale = scale; // and set its rotation
        }
    }

}

Upvotes: 1

Related Questions