Search Unity

  1. Get all the Unite Berlin 2018 news on the blog.
    Dismiss Notice
  2. Unity 2018.2 has arrived! Read about it here.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  4. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  5. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Scale Around Point - similar to Rotate Around

Discussion in 'Scripting' started by De-Panther, Mar 7, 2014.

  1. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    205
    Hey,

    So I had a problem, and I solved it, and because I saw lots of questions about it, but without a solution, here is how I solved it:

    Unity has Transform.RotateAround
    https://docs.unity3d.com/Documentation/ScriptReference/Transform.RotateAround.html
    Rotates the transform about axis passing through point in world coordinates by angle degrees.
    But it doesn't have ScaleAround

    In order to scale around a point in the world, you'll need this formula:

    GameObject Local Position
    A=Vector3(9,8,7)

    New pivot position(relative to object's parent)
    B=Vector3(4,5,6)

    Old scale Vector3(2,2,2)
    New scale Vector3(5,5,5)

    Find Object position relative to pivot(It's similar to put the game object as a child of a pivot object, and then get it's localPosition):
    A-B=C
    Vector3(9,8,7)-Vector3(4,5,6)=Vector3(5,3,1)

    Relative Scale(we need to check how much did the object scaled):
    RS=New Scale / Old Scale
    2.5=5 / 2

    Final Position:
    RS*C+B=FP

    Vector3.Scale(Vector3(2.5,2.5,2.5), Vector3(5,3,1)) + Vector3(4,5,6)
    Vector3(12.5,7.5,2.5) + Vector3(4,5,6)=Vector3(16.5,12.5,8.5)
    Vector3(16.5,12.5,8.5)

    So,
    (Relative Scale * Object Position Relative to Pivot) + Pivot Position

    Good luck :)
     
  2. MaRTiDoRe

    MaRTiDoRe

    Joined:
    Jul 4, 2011
    Posts:
    34
    I don't understand where do you get:

    Old scale Vector3(2,2,2)
    New scale Vector3(5,5,5)

    Where do you get those values from and why do you have two scale values?


    The rest is crystal clear.
     
    Last edited: Jul 3, 2014
  3. gregroberts

    gregroberts

    Joined:
    Nov 21, 2014
    Posts:
    25
    I've translated De-Panther's pseudocode into working code. Enjoy:

    var targetGO : GameObject;
    var pivotGO : Transform;

    function Start () {
    var A : Vector3 = targetGO.transform.position;
    var B : Vector3 = pivotGO.transform.position;

    var RS : float = 0.2; // relataive scale factor
    var startScale = targetGO.transform.localScale;
    var endScale = targetGO.transform.localScale *RS;

    var C : Vector3 = A-B; // diff from object pivot to desired pivot/origin

    // calc final position post-scale
    var FP : Vector3 = (C*RS)+B;

    // finally, actually perform the scale/translation
    targetGO.transform.localScale = endScale;
    targetGO.transform.position = FP;
    }
     
    tobetobe likes this.
  4. keenanwoodall

    keenanwoodall

    Joined:
    May 30, 2014
    Posts:
    503
    Thanks. Btw, protip, put code tags arounf your code so that it's formatted correctly and easy to read. Here's the official post on coding tags: http://forum.unity3d.com/threads/using-code-tags-properly.143875/
     
  5. trul

    trul

    Joined:
    Nov 15, 2013
    Posts:
    9
    antonsem likes this.
  6. KyleBlumreisinger

    KyleBlumreisinger

    Joined:
    Mar 6, 2017
    Posts:
    2
    So trul's code with parenting wasn't quite what I personally was looking for and I couldn't get it to work, but gregroberts's example code also didn't work for me out of the box, so I eventually made this:
    I've translated gregroberts's mostly-working (I'm assuming Java) code translation of De-Panther's pseudocode into fully functioning and tested C#:

    Code (CSharp):
    1. public void ScaleAround(GameObject target, Vector3 pivot, Vector3 newScale)
    2. {
    3.     Vector3 A = target.transform.localPosition;
    4.     Vector3 B = pivot;
    5.  
    6.     Vector3 C = A - B; // diff from object pivot to desired pivot/origin
    7.  
    8.     float RS = newScale.x / target.transform.localScale.x; // relative scale factor
    9.  
    10.     // calc final position post-scale
    11.     Vector3 FP = B + C * RS;
    12.  
    13.     // finally, actually perform the scale/translation
    14.     target.transform.localScale = newScale;
    15.     target.transform.localPosition = FP;
    16. }
    Usage:
    Code (CSharp):
    1. ScaleAround(targetGameObject, scaleCenterPivot, desiredFinalScale);
    Alternatively, if you would rather use a Transform / GameObject's position as the pivot, you can do:
    Code (CSharp):
    1. ScaleAround(targetGameObject, pivotGameObject.transform.position, desiredFinalScale);
    Just remember: It is extremely important that the pivot point be in the target's PARENT'S space. So if your target object has no parent, your pivot is in world space. If your target is a child of SomeGameObject, you pivot point must be in SomeGameObject's space. This can be accomplished with
    Code (CSharp):
    1. targetGameObject.transform.parent.InverseTransformPoint(pivot);
    if your pivot is in world space.

    Hope this helps someone who needed it as much as I did, thanks to everyone who contributed here, and happy coding!
     
    De-Panther likes this.
  7. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    205
    @KyleBlumreisinger , I'm happy that it helped someone after so many years :D

    I think that the "target" type on ScaleAround should be Transform.

    And maybe we can add a bool that ask if pivot is in parent space or world space.

    Also, now that I think about it, it works only if the scaling was unified.
    So iguess it shold be:
    Vector3 RS= new Vector3(newScale.x / target.transform.localScale.x, newScale.y / target.transform.localScale.y, newScale.z / target.transform.localScale.z);
    Vector3 FP = B + C.Scale(RS);

    But I'll have to test it.