jtth
jtth

Reputation: 886

Child object transform position,rotation,scale incorrect away from origin?

We have a parent object, let's call it RectangleParent, and we want to place child objects, in our case Squares, (a total determined at runtime within the a range of 1-10) within this surface. Both inside the bounds of our parent object, RectangleParent, evenly spaced from each other and from left to right in a maximum of two rows (5 items a row max, two rows max, equals 10 sqaures max).

EDIT start

enter image description here

end EDIT

Sample Unity pkg here

Correct example(s):

Ten (10) objects to place

tenObjs

Five (5) objects to place

fiveObjs

Current result

current

Notice our parent object at origin (parent objects being the elongated rectangles, child objects being the smaller squares). It's children are placed as desired, meeting all requirements. Placed within parent bounds, Two rows evenly spaced from each other within their parents bounds, and Each child object is evenly spaced from one another. As pictured in the Ten (10) objects example.

But then notice, for the parent object not located at origin - child objects (Squares) not placed within their parents boundaries, the spacing between the two rows does not fit within the parents bounds, and the objects are no longer squares (they look like rectangles now). However the child objects within each row are spaced evenly between one another so there is at least one desire met here.

If we assign Cube.transform .localPosition instead of .position

localPosition

At origin: The spacing between the rows is still correct but now the spacing between the child objects (squares) within each row is incorrect and as well all the child objects are not keeping within their parents bounds.

Away from origin: The two rows are aligned correctly, but the spacing between the two rows is incorrect. The two rows are not fitting within their parent objects boundaries. The child objects themselves have multiple problems. They are not squares and their spacing between one another is incorrect.

So what is wrong with our 3d placement math? How to fix our object placement, so that no matter where our parent object is, our children are placed within the bounds of their parent?

Code

public class NewBehaviourScript : MonoBehaviour {

    public int NumberOfObjectsToPlace = 10;   //Place 10 objects
    public int maxRows = 5; // how many objects can be placed in a row
    public int maxColumns = 2; // how many objects can be placed in a column

    public GameObject RectangleParent;  //the parentObject instance
    public GameObject CubePrefab;       //the cube prefab

    // Use this for initialization
    void Start () {
        PlaceObjects();
    }

    // Update is called once per frame
    void Update () {

    }

    void PlaceObjects()
    {
        Vector3 center = RectangleParent.GetComponent<MeshRenderer>().bounds.center;
        Vector3 size = RectangleParent.GetComponent<MeshRenderer>().bounds.size;
        Vector3 corner = -new Vector3(size.x / 2, 0, size.z / 2);
        float stepX = size.x / (maxColumns + 1);
        float stepZ = size.z / (maxRows + 2);
        int placedObjects = NumberOfObjectsToPlace;

        for (int i = 0; i < placedObjects; i++)
        {
            GameObject Cube = Instantiate(CubePrefab);
            Cube.transform.parent = RectangleParent.transform;
            Cube.transform.localRotation = Quaternion.identity;
            Cube.transform.position = corner + new Vector3(stepX, 
                center.y + 0.15f, 
                stepZ * 1.5f + i * stepZ
            );

            if (i == maxRows - 1)
            {
                i -= maxRows;
                placedObjects -= maxRows;
                stepX += size.x / (maxColumns + 1);
            }
        }
    }

}

(thanks to @Ali-Baba for all their help)

Upvotes: 0

Views: 560

Answers (1)

derHugo
derHugo

Reputation: 90570

You have to use the position and directions of RectangleParent like

Cube.transform.position = RectangleParent.transform.position 

                          + corner.x * RectangleParent.transform.right 
                          + corner.y * RectangleParent.transform.up 
                          + corner.z * RectangleParent.transform.forward 

                          + stepX * RectangleParent.transform.right 
                          + (center.y + 0.15f) * RectangleParent.transform.up 
                          + (stepZ * 1.5f + i * stepZ) * RectangleParent.transform.forward;

or alternatively you should rather use localPosition. Problem here might be that if the scale of RectangleParent is not 1,1,1 the value of localPosition might get scaled along with it so you might want to do

Cube.transform.localPosition = new Vector3(
                                   corner.x / RectangleParent.transform.localScale.x, 
                                   corner.y / RectangleParent.transform.localScale.y, 
                                   corner.z / RectangleParent.transform.localScale.z)

                               + new Vector3(
                                   stepX / RectangleParent.transform.localScale.x, 
                                   center.y + 0.15f, 
                                   (stepZ * 1.5f + i * stepZ) / RectangleParent.transform.localScale.z
                               );

and then for resetting the scale correctly you might want to do

Cube.transform.localScale = new Vector3(
                                1 / RectangleParent.transform.localScale.x, 
                                1 / RectangleParent.transform.localScale.y, 
                                1 / RectangleParent.transform.localScale.z
                            );

enter image description here

using

private void PlaceObjects()
{
    var center = RectangleParent.GetComponent<MeshRenderer>().bounds.center;
    var size = RectangleParent.GetComponent<MeshRenderer>().bounds.size;
    var corner = -new Vector3(size.x / 2, 0, size.z / 2);
    var stepX = size.x / (maxColumns + 1);
    var stepZ = size.z / (maxRows + 2);
    var placedObjects = NumberOfObjectsToPlace;

    for (var i = 0; i < placedObjects; i++)
    {
        var cube = Instantiate(CubePrefab);

        cube.transform.parent = RectangleParent.transform;
        cube.transform.localRotation = Quaternion.identity;

        cube.transform.localPosition = new Vector3(
                                           corner.x / RectangleParent.transform.localScale.x,
                                           corner.y / RectangleParent.transform.localScale.y,
                                           corner.z / RectangleParent.transform.localScale.z
                                       )

                                       + new Vector3(
                                           stepX / RectangleParent.transform.localScale.x,
                                           center.y + 0.15f,
                                           (stepZ * 1.5f + i * stepZ) / RectangleParent.transform.localScale.z
                                       );

        cube.transform.localScale = new Vector3(
                                        1 / RectangleParent.transform.localScale.x,
                                        1 / RectangleParent.transform.localScale.y,
                                        1 / RectangleParent.transform.localScale.z
                                    );

        if (i != maxRows - 1) continue;

        i -= maxRows;
        placedObjects -= maxRows;
        stepX += size.x / (maxColumns + 1);
    }
}

Upvotes: 2

Related Questions