Search code examples
c#unity-game-enginegame-physics

Defining a relative point with rotations


I want to get a relative point (so it's current pos + a vector3 of directions)

so that when I rotate the gameObject it's still in the same relative point

Example: (say if it was 1 unit away from the gameObject in the x axis when rotation is 0, it should be 1 unit away form the gameObject in the z axis when rotation is -90)

here's what I tried: (center is a vector3 of the distance relative to the gameObject)

boxPos = new Vector3(
    center.x + transform.position.x + (transform.rotation.eulerAngles.y * (1 / 360) * center.x),
    center.y + transform.position.y,
    center.z + transform.position.z + (0.5f - (transform.rotation.eulerAngles.y * (1 / 360) * center.z))
    );

any way how to do so?

After many suggestions... here're the results:

TEST 1:

Code:

private void OnDrawGizmos()
{
    //center is a value I defined... it is the relative point
    //no need to care about extents... that's just box size
    Vector3 objectPosition = transform.position;
    Quaternion rotation = transform.rotation;
    boxPos = (rotation * (center - objectPosition)) + objectPosition;
    Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale);
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(boxPos, new Vector3(extents.x * 2, extents.y * 2, extents.z * 2));
}

Result:

0-0-0 POSITION: it renders as if it was shifted center/-2 units away from the expected point (as expected from the other notices).

ROTATION: makes it behave weirdly

MOVEMENT: doesn't affect it at all

OTHER NOTICES: boxPos is just center/-2 (so if center is 1, -2, 3 boxPos would be -0.5, 1, -1.5)

TEST 2:

Code:

private void OnDrawGizmos()
{
    //no need to care about extents... that's just box size
    //first child of the object is just an empty object... shifted by center values... this is always in the intended relative point of the object
    boxPos = transform.TransformPoint(gameObject.transform.GetChild(0).position);
    Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale);
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(boxPos, new Vector3(extents.x * 2, extents.y * 2, extents.z * 2));
}

Result:

0-0-0 POSITION: it rendered perfectly as expected.

ROTATION: makes it shift away (but around) from the object.

MOVEMENT: also makes it shift way in the direction of movement (with a shift of value: position * (center/2) which makes the overall movement *1.5 of the expected movement every 1 unit in any direction)

TEST 3:

Code:

private void OnDrawGizmos()
{
    //no need to care about extents... that's just box size
    //first child of the object is just an empty object... shifted by center values... this is always in the intended relative point of the object
    boxPos = transform.TransformPoint(transform.InverseTransformPoint(gameObject.transform.GetChild(0).position));
    Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale);
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(boxPos, new Vector3(extents.x * 2, extents.y * 2, extents.z * 2));
}

Result:

0-0-0 POSITION: it rendered perfectly as expected.

ROTATION: makes it shift away (but around) the object.

MOVEMENT: it works perfectly as expected.

TEST 4:

Code:

private void OnDrawGizmos()
{
    //center is a value I defined... it is the relative point
    //no need to care about extents... that's just box size
    Vector3 objectPosition = transform.position;
    Quaternion rotation = transform.rotation;
    point = transform.TransformPoint(transform.InverseTransformPoint(gameObject.transform.GetChild(0).position));
    boxPos = (rotation * (point - objectPosition)) + objectPosition;
    Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale);
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(boxPos, new Vector3(extents.x * 2, extents.y * 2, extents.z * 2));
}

Result:

0-0-0 POSITION: it rendered perfectly as expected.

ROTATION: makes it shift away (but around) the object.

MOVEMENT: it works perfectly as expected.

TEST 5:

Code:

private void OnDrawGizmos()
{
    //center is a value I defined... it is the relative point
    //no need to care about extents... that's just box size
    //first child of the object is just an empty object... shifted by center values... this is always in the intended relative point of the object
    boxPos = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale).inverse.MultiplyPoint(transform.GetChild(0).position);
    Gizmos.matrix = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale);
    Gizmos.color = Color.red;
    Gizmos.DrawWireCube(boxPos, new Vector3(extents.x * 2, extents.y * 2, extents.z * 2));
}

Result:

0-0-0 POSITION: it rendered perfectly as expected.

ROTATION: it works perfectly as expected.

MOVEMENT: it works perfectly as expected.


Solution

  • For your specific use case of having to cancel out the rotation and scale but not the position of a child, I would do this:

    Vector3 boxPos = Matrix4x4.TRS(Vector3.zero, transform.rotation, transform.localScale)
            .inverse.MultiplyPoint(transform.GetChild(0).position);
    

    Normally, I'd say you're already using a transform so just use InverseTransformPoint to calculate the local position of the object and if you want to convert back to a world position you can use TransformPoint:

    Transform target;
    Vector3 relativePos;
    
    // ...
    
    Vector3 relativePos = transform.InverseTransformPoint(target.position);
    
    // ...
    
    Vector3 worldPos = transform.TransformPoint(relativePos);