I would like to transform a rigidbody's world velocity into a local velocity based on a normal direction.

When the rigidbody is moving towards and within a range of a object, I use a raycast to determine the hit position and normal of the face it will collide with. I have the velocity of the RB in world space, but I would like to have it in the normal's reference frame.

I know a Transform component can do InverseTransformDirection(), but seeing as the normal is most likely not aligned to its transform, this is not going to work.

I want to know the velocity an object collided with a face, but only in the face's normal direction. The outcome of this is to apply a force to the rigidbody in the normal's direction and thus stopping the rigidbody from moving any closer to the hit point. The force will be calculated by looking at the component of the rigidbody's velocity that is in the same direction the normal. My thinking is, that if I can get the RB velocity into the reference frame of the normal, it will be just the UP component that I need to look at: the speed the RB is moving along the normal towards the hit point.

If you can imagine (all in world space) a ball dropping on the floor: when this ball is one radius away from the floor, there will be a contact point and the normal will be perpendicular to the floor. To arrest the fall of the ball, a force in the direction of the normal is applied (so UP). The strength of this force is the down component of the velocity. If the ball was moving horizontally while dropping, the DOWN component of the velocity that matches the normal direction in this case is what I am interested in.

Basically I want the velocity of the RB that as seen from the normal along its axis. Almost like saying I want to transform the world space velocity into a local mesh face space, but only the UP axis.

  • 1
    \$\begingroup\$ A position and a normal is not enough to define a local coordinate system in 3D. We still have a degree of freedom which is rotation around the axis of the normal, so you need to fix some other non-parallel vector. It's not clear to me yet which choice would be appropriate for that. Can you edit your question to give us more context about how you're trying to use this local coordinate space, or the end goal you want to achieve with this transformed velocity? \$\endgroup\$
    – DMGregory
    Sep 29, 2022 at 13:17

1 Answer 1


If you just want to do something with the component of the velocity parallel to the normal, that's just a vector projection, and you don't need to do a full transformation into a local coordinate system with that ambiguous degree of freedom.

Assuming your normal has unit length, that's:

// Measure incoming speed along normal direction.
float normalSpeed = Vector3.Dot(rb.velocity, normal);

// Cancel out the velocity in that direction.
rb.AddForce(-normalSpeed * normal, ForceMode.VelocityChange);

This is also available as a built-in function in Unity:

    -Vector3.Project(rb.velocity, normal), 

This is why it's important to always frame questions in terms of the ultimate goal you want to achieve, not the stepping stone you thought of to get there. If you don't understand the problem well enough yet to fully solve it, then you might not be picking the right stepping stone, leading to something called the XY Problem. Here, asking to transform to local coordinates was a red herring, that made the solution more complicated than it needed to be.

  • \$\begingroup\$ I understand 100%. I think a part my problem was that I have been thinking about transforming the space of vector into another's space for a while. Because of this I was trying to force it to be the solution. Thank you for helping me. \$\endgroup\$ Sep 30, 2022 at 8:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .