Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by beau101023 · Sep 01, 2016 at 09:22 PM · scaleworldspacelocalpositionroundingtransform.transformpoint

Version of Transform.TransformPoint which is unaffected by scale?

Is there a scale-independent version of Transform.TransformPoint?

I am trying to convert a position to a localized position relative to an object, and then round that position. The problem is that with the scale dependent Transform.TransformPoint method, the position is rounded to fractions of the object's scale instead of to an absolute distance away from the center of the object. Any help would be appreciated, thanks.

My current code:

 // makes the point's position local to the gameobject that was hit by the raycast
 tTemp.position = hit.collider.gameObject.transform.InverseTransformPoint(hit.point);
 
 // rounds it to the apropriate amount
 tTemp.position = new Vector3
 (
     Mathf.Round(tTemp.position.x * gridSize)/gridSize,
     Mathf.Round(tTemp.position.y * gridSize)/gridSize,
     Mathf.Round(tTemp.position.z * gridSize)/gridSize
 );
 // translates the position back into world space
 tTemp.position = hit.collider.gameObject.transform.TransformPoint(tTemp.position);
Comment
Add comment · Show 9
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image b1gry4n · Sep 01, 2016 at 11:15 PM 0
Share

have you tried multiplying the position by the scale? You would do this before you convert from local to global space.

 tTemp.position = new Vector3(tTemp.position.x * hit.transform.localScale.x, tTemp.position.y * hit.transform.localScale.y, tTemp.position.z * hit.transform.localScale.z);
avatar image beau101023 b1gry4n · Sep 02, 2016 at 12:32 AM 0
Share

I've thought about that, but it only seems to make the translated position further away from the comparison object.

avatar image b1gry4n beau101023 · Sep 02, 2016 at 09:41 AM 0
Share

I think the problem is the scale itself. If you notice when you have a scaled object and you place a nonscaled object as a child, that childs displayed scale changes relative to its parent. Its best practice to have your assets scale be 1,1,1. If you need to scale art assets thats usually fine as its just a visual display, but if youre trying to make objects children of scaled objects and do what youre trying to do it becomes a headache. Have you tried placing stuff on a non-scaled object?

avatar image andrew-lukasik · Sep 02, 2016 at 10:12 AM 1
Share

Is tTemp a child of hit.collider.transform?

Judging by the way you use both TransformPoint and InverseTransformPoint (as if they were the same thing) one can come to conclusion that you confuse local and world positions here.

tTemp.position - is a World Space position

hit.point - is a World Space position too

InverseTransformPoint() - returns Local Space position (and expects World Space position as argument)

TransformPoint() - returns World Space position (and expects Local Space position as argument)

transform.position - assign here ONLY World Space positions (and returns World Space position)

transform.localPosition - assign here ONLY Local Space position (and returns Local Space position)


So then, this is invalid:

 // makes the point's position local to the gameobject that was hit by the raycast
  tTemp.position = hit.collider.gameObject.transform.InverseTransformPoint(hit.point);
 
 //comment: No. It does not. Assigning Local Space position to inheritly World Space transform.position does not make it local

syntactically fixed version:

 //World Space solution:
  tTemp.position = hit.point;
 //OR
 //Local Space solution:
 rTemp.parent = hit.collider.transform;
 rTemp.localPosition = hit.collider.transform.InverseTransformPoint( hit.point );


Another troubling line:

 // translates the position back into world space
  tTemp.position = hit.collider.gameObject.transform.TransformPoint(tTemp.position);
 
 //comment: No it does not. This line contradicts itself...
 //TransformPoint expects Local Space position as argument not World Space one
 //(which tTemp.position definitely is)
 //So... you end up here incorrectly converting tTemp.position (World Space) to hit.collider.transform's Local Position (which will result in garbage position) and then assing it to tTemp.position again... not good
avatar image b1gry4n andrew-lukasik · Sep 02, 2016 at 10:37 AM 0
Share

this question is a spinoff of : http://answers.unity3d.com/questions/1237065/rounding-a-position-against-the-surface-of-an-obje.html#comment-1237479

avatar image andrew-lukasik b1gry4n · Sep 02, 2016 at 10:46 AM 0
Share

I think your code will work when you no longer confuse World and Local spaces. So really make sure you understand the distinction first

EDIT: I mistook you sir for an author of this question : ) sorry about that!

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
15
Best Answer

Answer by villevli · Sep 02, 2016 at 12:04 PM

I made a version of Transform.TransformPoint which is unaffected by scale as the title of this question suggested. I don't know if it helps with the problem? This is an extension class that adds unscaled versions of the TransformPoint methods to the Transform class.

 using UnityEngine;
 using System.Collections;
 
 public static class TransformExtensions
 {
     public static Vector3 TransformPointUnscaled(this Transform transform, Vector3 position)
     {
         var localToWorldMatrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
         return localToWorldMatrix.MultiplyPoint3x4(position);
     }
 
     public static Vector3 InverseTransformPointUnscaled(this Transform transform, Vector3 position)
     {
         var worldToLocalMatrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one).inverse;
         return worldToLocalMatrix.MultiplyPoint3x4(position);
     }
 }



Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image beau101023 · Sep 02, 2016 at 02:40 PM 0
Share

This actually worked even better than my proposed solution above. Thanks a bunch!

avatar image FlightOfOne · Feb 14, 2021 at 01:19 AM 0
Share

You are a life saver!

avatar image Bunny83 · Feb 14, 2021 at 02:30 AM 0
Share

Note that those would be more efficient:

 public static class TransformExtensions
 {
     public static Vector3 TransformPointUnscaled(this Transform transform, Vector3 position)
     {
         return transform.position + transform.rotation * position;
     }
 
     public static Vector3 InverseTransformPointUnscaled(this Transform transform, Vector3 position)
     {
         position -= transform.position;
         return Quaternion.Inverse(transform.rotation) * position;
     }
 }

Creating a matrix out of the position and rotation and then perfor$$anonymous$$g a matrix vector multiplication every time is quite a lot of overhead. Let alone calculating the inverse of a 4x4 matrix. The inverse of a quaternion is much simpler to calculate.


Creating a matrix makes only sense if you store it and use it multiple times on many points / vectors

avatar image Bunny83 Bunny83 · Feb 14, 2021 at 02:35 AM 0
Share

Though that said there should never be the need for this extension. A Transform component represents a new seperate coordinate system. If you don't want a scale, you shouldn't scale the transform in the first place. If a model should be scaled, make the model a child of the transform that represents your coordinate system and just scale that child and keep the parent untouched.

avatar image Tortuap Bunny83 · Mar 06, 2021 at 06:59 PM 0
Share

Easy to say, but sometime you just want to position a point relative to a transform using a local offset, without any scaling co$$anonymous$$g into play.

Show more comments
avatar image
3

Answer by b1gry4n · Sep 02, 2016 at 11:25 AM

I have never done anything like this so I am unsure. For me its easier to wrap my head around when I start separating things. I think the problem might be (as andrew points out) you are referencing the transforms.position in the last bit. I dont know your setup, but I am guessing the object is not a child of anything. You dont want to plug in "transform.position" into the TransformPoint part as you are getting the transforms world coordinates. You want the local coordinates.

for example:

if the hit point is (45.82, 21.02, 16.57), translating that to the objects local coordinates might make the local coordinates be (2.5,4.2,-3.92). Based off your grid size, rounding that might give you something like (2,4,-4). You want to plug that last bit into the TransformPoint part. Right now you are plugging in its world coordinates. So in your code, youve moved tTemp to the new local position (2,4,-4), but in world space. Now tTemp sits at (2,4,-4) in world coordinates when it should be closer to the hit.point values. From there you are plugging in that world position as a local value to the object you are referencing, which could be something wild like (-50, -5, 73). hopefully that makes sense.

     // The hit point is translated to local space from world space
     Vector3 localSpace = hit.collider.gameObject.transform.InverseTransformPoint(hit.point);
      
      // the local position is rounded to the grid
      Vector3 localSnappedGrid = new Vector3
      (
          Mathf.Round(localSpace.x* gridSize)/gridSize,
          Mathf.Round(localSpace.y* gridSize)/gridSize,
          Mathf.Round(localSpace.z* gridSize)/gridSize
      );
      // the local position is translated to world space and the object is placed
      tTemp.position = hit.collider.gameObject.transform.TransformPoint(localSnappedGrid);


PS: I had it like this in the other question you asked, you changed it and put transform.position :p

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image andrew-lukasik · Sep 02, 2016 at 12:00 PM 0
Share

I think you sir solved @beau101023 's problem here

avatar image beau101023 · Sep 02, 2016 at 02:20 PM 0
Share

That seems to do the same thing as my script though. You see, I was merely using tTemp.position as an intermediary storage variable just as you are doing with localSpace and localSnappedGrid. $$anonymous$$y problem appears to have been fixed by multiplying gridSize by Transform.lossyScale.

I think my problem was that in local space, the position of the object away from the center of the 'parent' is measured in parent-scales. So if the parent's scale was 9 on one axis, having the 'child' be 9 units away and converting to local space would return a 1 on that axis.

Thank you for all your help, @b1gry4n , @andrew-lukasik . It is very much appreciated. :)

Edit: I'm not sure about the etiquette on these things, so I'll just leave this question unanswered rather than marking my own answer correct.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

57 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Image with material is not render 0 Answers

How to follow the player without moving camera? 0 Answers

How to aply force to parent gameObject using childs local space coordinates? 0 Answers

Class member Vector3 based on local transform 1 Answer

Convert LineRenderer SetPosition from World to Object Space 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges