Home > OS >  C# Vector3 Quaternion rotating from a direction to the normal direction of surface below but only by
C# Vector3 Quaternion rotating from a direction to the normal direction of surface below but only by

Time:05-04

Im using Unity3D Engine for this project.

My goal is to rotate an object's up direction about half way to the same direction as the surface it is standing on, the grounds normal.

Normally you could easily achieve this with the following code:

  fencer.transform.rotation = Quaternion.FromToRotation(fencer.transform.up, hit.normal) * fencer.transform.rotation;

fencer.transform.up is the objects up direction, also a Vector3, we are setting this to the normal of the hit surface. hit.normal is a Vector3, the normal of the surface below. This works perfectly.

Now Im trying to only 'half' rotate the object to the grounds surface:

var halfNormal = (fencer.transform.up - hit.normal);
                        if (halfNormal.y < 0)
                            halfNormal *= -1;
                        fencer.transform.rotation = Quaternion.FromToRotation(fencer.transform.up, halfNormal) * fencer.transform.rotation;

So the code above is trying to calculate the difference between the normal's vector and the fencer's up vector, basically trying to calculate what would be 'half of the normal'. So that when I apply the FromToRotation() with the new halfNormal as the `ToRotation. It should only rotate the object half way to the grounds normal, basically only rotating 50% of the way as opposed to before were we rotate 100% of the way.

The problem is it doesnt work, I get very strange results this way.

How can I solve this problem and find the half of the normal? or is there a better approach where I can find 10% of the normal, or 75% or whatever percentage I choose?

I am very grateful for any help. Thanks.

CodePudding user response:

One way is to just use Quaternion.Slerp to interpolate 50% between your start and 100% rotated.

Quaternion goal =  Quaternion.FromToRotation(fencer.transform.up, hit.normal) 
        * fencer.transform.rotation;
fencer.transform.rotation = Quaternion.Slerp(fencer.transform.rotation, goal, 0.5f);

Another way is to do your previous method but convert the delta to angle/axis then cut the angle in half before applying it. This could be more useful if you need to know the angle and/or axis for other purposes:

Quaternion delta = Quaternion.FromToRotation(fencer.transform.up, hit.normal);
delta.ToAngleAxis(out float angle, out Vector3 axis);
Quaternion halfDelta = Quaternion.AngleAxis(0.5f * angle, axis);
fencer.transform.rotation = halfDelta * fencer.transform.rotation;
  • Related