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);
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);
}
}
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