- Home /
RaycastHit normal only pitch+yaw
Hi,
I use the normal of RaycastHit to place an gameObject alligned with terrain. The problem I face however is that it wants to use Pitch+Yaw+Roll for the rotation, but I want it to only use Pitch+Yaw (so Roll will be 0), how to get/do this?
-edit, here is a picture to better show what I am trying to do; the green arrow is the direction the object should face on the respective slope:
Answer by hoekkii · Aug 14, 2017 at 08:54 PM
Short answer:
public static void Normal2PitchYaw(Vector3 normal, out float pitch, out float yaw)
{
yaw = -Mathf.Asin(normal.x) * Mathf.Rad2Deg;
pitch = Mathf.Atan2(normal.z, normal.y) * Mathf.Rad2Deg;
}
Long answer:
What do you really want to do?
Because working with pitch, yaw, roll can be a real pain in the.
So I would recommend to use quaternions instead.
If you really need pitch, yaw roll..
Got all the info from this page: https://stackoverflow.com/questions/1568568/how-to-convert-euler-angles-to-directional-vector
You will see on the page; to go from pitch, yaw to a direction vector you'll need this formula:
x = cos(yaw)*cos(pitch)
y = sin(yaw)*cos(pitch)
z = sin(pitch)
To convert this to Unity you can't copy paste it, because in Unity the Y-axis is up. so you will get this:
x = -sin(yaw) * cos(pitch)
y = cos(yaw) * cos(pitch)
z = sin(pitch)
You now can invert the equation to get from direction to pitch and yaw. So you would expect:
pitch = asin(normal.z)
yaw = -atan2(normal.x, normal.y)
This is a valid answer, but when applying it raw to a transform like transform.eulerAngles = new Vector3(pitch, 0, yaw)
wouldn't get the expected result because the rotation will (as a rough explanation) be Quaternion.Euler(pitch, 0, 0) * Quaternion.Euler(0, 0, yaw)
but the multiplication should be the other way around. which leads us to:
yaw = -asin(normal.x)
pitch = atan2(normal.z, normal.y)
Edit:
Thank you for clarifying your question.What you want to do is way more straight forward than the story above.
The target is to get the forward direction vector of the slope, which can be converted in to a rotation.
You can use the cross product to get the right (as in direction) vector by doing the cross product of the normal and the up direction.
With the normal and the right vector you can do a cross product again to get the forward vector.
Which in code looks like:
static Vector3 Normal2Forward(Vector3 normal, Vector3 up)
{
var right = Vector3.Cross(normal, up);
return Vector3.Cross(normal, right);
}
void Foo()
{
var forward = Normal2Forward(hit.normal, Vector3.up);
var rotation = Quaternion.LookRotation(forward, Vector3.up);
}
Hi @hoekkii , hi @andrew-lukasik ,
Thanks both of your for your suggestions, however they don't entirely do what I am trying to achieve (almost though). Sorry for being a bit unclear earlier. I want to use this to attach objects to surfaces/floors/terrain, however I want to let the objects always face the direction of the slope. I can explain this better with an image (the green arrow is the direction the object should face on the respective slope):
Thanks for your clear & comprehensive way of explaining. On top of that your code/solution is very clean. :-)
Hi @hoekkii , I noticed you made a little error in your code. It should be Vector3 right = Vector3.Cross(normal, up*-1); (you missed the * -1), otherwise all the objects are placed backwards.
Answer by andrew-lukasik · Aug 14, 2017 at 07:33 PM
//calculate generalDirection:
Vector3 generalDirection = Vector3.ProjectOnPlane( hit.normal , Vector3.up ).normalized;
//generalDirection will be of length 0 when normal is parrallel to Vector3.up (flat terrain etc)
if( generalDirection==Vector3.zero)
{
//use predefined direction instead (or whatever suits your need):
generalDirection = new Vector3( 1f , 0f , 1f ).normalized;
}
//calculate preciseDirection:
Vector3 preciseDirection = Vector3.ProjectOnPlane( generalDirection , hit.normal ).normalized;
//calculate rotation:
Quaternion rotation = Quaternion.LookRotation( preciseDirection , hit.normal );
Your answer
Follow this Question
Related Questions
RaycastHit.normal Problem 1 Answer
What is a RaycastHit normal? 1 Answer
Rotating a character relative to the ground's rotation 1 Answer
Why are RaycastHit surface normals of corners not interpolated or otherwise correct? 1 Answer
rigidBody is heading to a slightly different angle to where im calculating it would be using Reflect 1 Answer