Basic idea of Quaternion y axis 90 degree rotate - unity3d

I want to rotate the object around y axis 90 degree.
What I want to do is very simple
getPosition(Quaternion rotation)
rotation.y = rotation.y + 90.0f;
_rotateTarget.rotation = rotation;
it shows error.
I googled around and found I need to understand Quaternion
However I can't find first clue to rotate object simply 90 degree.
Is there any help??

If you want to rotate an object smoothly to a target rotation you can use Quaternion.Slerp. The following script lets you set the x, y and z rotation.
[Header("Settings")]
public Vector3 targetRotation;
public float rotationSpeed = 5;
private Quaternion currentTargetRotation;
// Start is called before the first frame update
void Update()
{
if (currentTargetRotation.eulerAngles != targetRotation)
currentTargetRotation.eulerAngles = targetRotation;
transform.rotation = Quaternion.Slerp(transform.rotation, currentTargetRotation, rotationSpeed * Time.deltaTime);
}

A Quaternion has not three but rather four components x, y, z and w! And they all move in the range -1 to 1.
=> Never touch the individual components of a Quaternion except you really know exactly what you are doing!
For rotating the object on the global Y-axis you rather want to use e.g. Quaternion.Euler as the name suggests generates a Quaternion rotation from the given Euler space angles.
Returns a rotation that rotates z degrees around the z axis, x degrees around the x axis, and y degrees around the y axis; applied in that order.
rotation *= Quaternion.Euler(0, 90, 0);
// Or also
//rotation *= Quaternion.Euler(Vector3.up * 90);
_rotateTarget.rotation = rotation;
Or if you want to rotate in any given axis you can also use Quaternion.AngleAxis
rotation *= Quaternion.AngleAxis(90, Vector3.up);
_rotateTarget.rotation = rotation;
And then you always combine two Quaternion using the multiplication * operator.
var final = rotA * rotB;
basically means first apply the rotation rotA then starting from there additionally apply the rotB.
rotation *= rotB;
is just a shorthand for writing
rotation = rotation * rotB;

Related

How to convert from direction and rotation around y-axis to Quaternion in Unity

How to convert from direction and rotation around y-axis to Quaternion in Unity.
I want to rotate the object that is up-wards.
The object rotate certain direction and then rotate around an axis (object's local up-wards).
I implemented it as follows, and pressed the A button and the B button.
However, obj (button B) sometimes becomes a different quaternion (button A).
Why is this? Is there a solution?
if (Input.GetKeyUp(KeyCode.A)){
obj.transform.rotation = Quaternion.EulerAngles((float)Random.Range(0,359), (float)Random.Range(0,359), (float)Random.Range(0,359));
}
if (Input.GetKeyUp(KeyCode.B)){
// decomposition of vector and rotation around axis
Vector3 up_axis = new Vector3(0f, 1f, 0f);
Vector3 fwd = obj.transform.rotation * up_axis;
Quaternion q = obj.transform.rotation;
// create quaternion
Quaternion objective_rot_wo_w = Quaternion.FromToRotation(up_axis, fwd);
Quaternion diff = objective_rot_wo_w * Quaternion.Inverse(q);
diff.ToAngleAxis(out float _tmpAngle, out Vector3 _tmpAxis);
float around_y_angle = _tmpAngle;
// set
Quaternion rot = objective_rot_wo_w;
Quaternion rot_z = Quaternion.AngleAxis(around_y_angle, up_axis);
obj.transform.rotation = rot * rot_z;
}
Thank you for your cooperation.

Unity - rotated objects flips in a strange way when using Quaternions

I'm trying to create a system in VR in which an object rotation follows the rotation of the player's hand. Unfortunately, when the hand rotates at a high angle, the rotated object flips in a strange way as if it had a problem with the rotation change from 360 degrees to 0. I tried many ways to solve this problem, but each one that worked did not allow me to change "sensitivity" on the basis of:
1 - target is rotating 1: 1 ratio with hand
2 - target is rotating twice as much as hand
etc.
// In FixedUpdate
Quaternion deltaRotation = Quaternion.Inverse(target.rotation) * hand.rotation;
deltaRotation.ToAngleAxis(out float angle, out Vector3 axis);
target.rotation *= Quaternion.AngleAxis(angle * sensitivity, axis);
Any help would be appreciated!
So the problem is in
Quaternion deltaRotation = Quaternion.Inverse(target.rotation) * hand.rotation;
if the sensitivity is != 1 these objects rotations get desynchronized so the deltaRotation will not give you the value you expect. You probably wanted to check how much hand rotated since last frame, like that:
Quaternion _lastFrameRotation;
void Awake()
{
_lastFrameRotation = transform.rotation;
}
private void FixedUpdate()
{
Quaternion deltaRotation = Quaternion.Inverse(_lastFrameRotation) * transform.rotation;
deltaRotation.ToAngleAxis( out float angle, out Vector3 axis );
target.rotation *= Quaternion.AngleAxis( angle * sensitivity, axis );
_lastFrameRotation = transform.rotation;
}

Unity: GameObject bug in rotation axis

In the GIF above I am moving the plane with the mouse up and down. Watch how when I rotate the plane on its Z axis the plane still moves up and down even if the plane is side ways now. That is my bug. Why is this happening? What is wrong with my code? I think I am using the global axis and not the gameobjects axis. How do I fix this please.
x += Input.GetAxis("Mouse X") * xMouseSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * yMouseSpeed * 0.02f;
if (Input.GetKey(KeyCode.Q))
{
rotZ += Time.deltaTime * 50f;
}
if (Input.GetKey(KeyCode.E))
{
rotZ -= Time.deltaTime * 50f;
}
Quaternion rotation = Quaternion.Euler(y, x, rotZ);
planeBodyToMove.localRotation = rotation;
What happens is that the localRotation is just the rotation in relation to the parent object.
The rotation of the transform relative to the transform rotation of the parent.
Or in other words: The localRotation is not local to the object itself but rather a rotation in the local space of the parent (or Unity world space if there is no parent). It does not mean that you rotate around your local Y axis necessarily. It applies the rotations in the parent's local space in the order Z, X, Y .. that is why sometimes you actually don't note the difference until you rotate Y!
As you can see here the same thing happens also without your code by just doing the rotation via the Inspector
Or to demonstrate it a bit better lets see what happens if we rotate it the way you actually want it to rotate:
as you can see as soon as one axis already is rotated, changing another axis now changes all three rotation values.
Solution
So how to solve this?
Usually I'm to lazy to do Quaternion calculations myself → I let the Transform do this for me ^^
Instead of storing the expected rotation in fields and apply it everytime by converting it into a Quaternion you can directly use Transform.Rotate which rotates the object actually using its own local axis:
// Just a question of taste but I would prefer to have
// values that belong together in one single struct instead of multiple fields
public Vector2 mouseSensitivity = Vector3.one;
private void Update()
{
var xDif = Input.GetAxis("Mouse X") * mouseSensitivity.x;
var yDif = - Input.GetAxis("Mouse Y") * mouseSensitivity.y;
var zDif = 0f;
if (Input.GetKey(KeyCode.Q))
{
zDif= Time.deltaTime * 50f;
}
else if (Input.GetKey(KeyCode.E))
{
zDif= -Time.deltaTime * 50f;
}
// Wihout the optional space parameter uses local space by default
planeBodyToMove.Rotate(new Vector3(xDif, yDif, zDif));
}
As you can see now each rotation is actually applied in the plane's local axis:

Object does not rotate in the correct direction from Atan2 to Quaternion

I am trying to rotate an object on its z axis, given a point I calculated at an angle with Atan2 function. Then I create a Quaternion to enter it in the rotation of the object. However, it does not rotate in the supposedly correct direction. If I diagram the angles given by the Atan2 functions, I visualize a clockwise system of angles, but if I diagram the angles that should be so that my object is rendered in the correct direction, I visualize an anti-clockwise system. The solutions creating a dictionary with the values received by the Atan2 function as keys and their values are the angles with which the object will rotate the correct direction. But I still don't understand what is happening. I hope someone can help me understand it because there is no worse solution than the one that solves but without knowing what is happening.
public class ArrowMovement : MonoBehaviour
{
public Vector2Variable currentPlayerDirection;
public Vector3Variable currentPlayerPosition;
public InputAxis inputAxis;
private float anglePassed;
private Dictionary<float, float> realAngles = new Dictionary<float, float>();
void Awake()
{
realAngles.Add(-135, -135);
realAngles.Add(-90, 180);
realAngles.Add(-45, 135);
realAngles.Add(0, 90);
realAngles.Add(45, 45);
realAngles.Add(90, 0);
realAngles.Add(135, -45);
realAngles.Add(180, -90);
}
void Update()
{
Vector3 offsetVector = new Vector3(0.2f, 0.05f, 0);
transform.position = currentPlayerPosition.Value;
// Rotation
float angle = Mathf.Atan2(inputAxis.horizontal, inputAxis.verticall) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.Euler(0, 0, realAngles[angle]);
transform.rotation = rotation;
}
}
First of all, you should know what inputAxis is.
I can guess from your diagram that you expect that for inputAxis.verticall == 0 the angle must be 0. Let's look at Mathf.Athan2(y,x) - it is equivalent to arctan(y/x), so result will be zero only when y is zero. But, in your code Mathf.Atan2(inputAxis.horizontal, inputAxis.verticall) will give 0 when inputAxis.horizontal == 0 - it is vertical direction (your first diagram).
Second issue - wrong rotation direction. This can happen when one of the input axes is inverted. Probably, inputAxis is measured in a different coordinate system relative to your object, i.e. Z of your object is -Z of your inputAxis. Anyway, inputAxis.verticall can be inverted
float angle = Mathf.Atan2(inputAxis.horizontal, -inputAxis.verticall) * Mathf.Rad2Deg;
Also, you should avoid solving a simple geometric problem by "creating a dictionary" or anything like that. Even if you don't know how inputAxis works and result is wrong - make two step to fix it: 1. fix rotation direction - just invert the angle Quaternion.Euler(0, 0, -angle); 2. fix the zero position - add some static rotation. It is 90 deg in your case Quaternion.Euler(0, 0, 90 - angle). And it is the second way to solve the problem.
Creating a dictionary is not the best way because it does not take into account the angles between the ones you set so to convert from one diagram to the other I would create a function that looks like:
float ChangeAngleDiagram(float angle) {
return -(angle + 90f)+180;
}

Vertex position relative to normal

In a surface shader, given the world's up axis (and the others too), a world space position and a normal in world space, how can we rotate the worldspace position into the space of the normal?
That is, given a up vector and a non-orthogonal target-up vector, how can we transform the position by rotating its up vector?
I need this so I can get the vertex position only affected by the object's rotation matrix, which I don't have access to.
Here's a graphical visualization of what I want to do:
Up is the world up vector
Target is the world space normal
Pos is arbitrary
The diagram is bidimensional, but I need to solve this for a 3D space.
Looks like you're trying to rotate pos by the same rotation that would transform up to new_up.
Using the rotation matrix found here, we can rotate pos using the following code. This will work either in the surface function or a supplementary vertex function, depending on your application:
// Our 3 vectors
float3 pos;
float3 new_up;
float3 up = float3(0,1,0);
// Build the rotation matrix using notation from the link above
float3 v = cross(up, new_up);
float s = length(v); // Sine of the angle
float c = dot(up, new_up); // Cosine of the angle
float3x3 VX = float3x3(
0, -1 * v.z, v.y,
v.z, 0, -1 * v.x,
-1 * v.y, v.x, 0
); // This is the skew-symmetric cross-product matrix of v
float3x3 I = float3x3(
1, 0, 0,
0, 1, 0,
0, 0, 1
); // The identity matrix
float3x3 R = I + VX + mul(VX, VX) * (1 - c)/pow(s,2) // The rotation matrix! YAY!
// Finally we rotate
float3 new_pos = mul(R, pos);
This is assuming that new_up is normalized.
If the "target up normal" is a constant, the calculation of R could (and should) only happen once per frame. I'd recommend doing it on the CPU side and passing it into the shader as a variable. Calculating it for every vertex/fragment is costly, consider what it is you actually need.
If your pos is a vector-4, just do the above with the first three elements, the fourth element can remain unchanged (it doesn't really mean anything in this context anyway).
I'm away from a machine where I can run shader code, so if I made any syntactical mistakes in the above, please forgive me.
Not tested, but should be able to input a starting point and an axis. Then all you do is change procession which is a normalized (0-1) float along the circumference and your point will update accordingly.
using UnityEngine;
using System.Collections;
public class Follower : MonoBehaviour {
Vector3 point;
Vector3 origin = Vector3.zero;
Vector3 axis = Vector3.forward;
float distance;
Vector3 direction;
float procession = 0f; // < normalized
void Update() {
Vector3 offset = point - origin;
distance = offset.magnitude;
direction = offset.normalized;
float circumference = 2 * Mathf.PI * distance;
angle = (procession % 1f) * circumference;
direction *= Quaternion.AngleAxis(Mathf.Rad2Deg * angle, axis);
Ray ray = new Ray(origin, direction);
point = ray.GetPoint(distance);
}
}