Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  4. 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:
    208
    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:
    515
    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
    I've created static method to scale target around the pivot:

    Code (CSharp):
    1. public static void ScaleAround(Transform target, Transform pivot, Vector3 scale) {
    2.         Transform pivotParent = pivot.parent;
    3.         Vector3 pivotPos = pivot.position;
    4.         pivot.parent = target;      
    5.         target.localScale = scale;
    6.         target.position += pivotPos - pivot.position;
    7.         pivot.parent = pivotParent;
    8.     }
     
    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!
     
    stenfeio and De-Panther like this.
  7. De-Panther

    De-Panther

    Joined:
    Dec 27, 2009
    Posts:
    208
    @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.
     
  8. stenfeio

    stenfeio

    Joined:
    Jan 18, 2015
    Posts:
    10
    This was excellent. It's easy to forget that final positions need to also be handled as we've come so much to rely on parenting...
     
    Last edited: Sep 3, 2018