- Home /
very specific question about rotating children opposite to rotation of parent using quaternions (or something like that)[solved]
ill have the script i use at the end of this, but its a spaghetti fest (seriously, its a nightmare down there you don't have to help if you don't want to). so ill simplify what i have so far; a main rigidbody which is using quaternion.slerp to rotate to the direction of the normal directly below it using a raycast (i don't know how this works exactly but i multiply a part of it by the rigidbody's rotation and another quaternion for rotation around the y axis and it just works) the rigidbody doesn't have gravity and has a constant local force applied to its y axis. also there's a camera as a child of the main rigidbody which only gets the x axis modified using quaternion.euler, in short that makes it work like a regular fps player sorta thing. what i want to do now is get the x rotation of the camera to not be effected by the rotation of the main rigidbody so it can look at something else while the main rigidbody changes its rotation. is this even possible? any advice?
#region
float xRot = Input.GetAxisRaw("Mouse X");
float yRot = Input.GetAxisRaw ("Mouse Y");
Vector3 rbRot = new Vector3(0f, xRot, 0f) * camsensitivity;
Vector3 camRot = new Vector3((-yRot * 1.6f), 0f, 0f) * camsensitivity;
//Debug.Log (camera.rotation);
if (camera.localEulerAngles.x > 270f){
//camera.rotation = Quaternion.Euler(90f, 0f, 0f);
//Debug.Log("euler is greater than 270");
}
if (camera.localEulerAngles.x > 80f && camera.localEulerAngles.x < 300f){
//camera.rotation = Quaternion.Euler(90f, 0f, 0f);
//Debug.Log("euler is less than 90");
}
//Debug.Log(manualangle);
//rotate towards normal
RaycastHit normalchek;
Physics.Raycast (transform.position, transform.TransformDirection(Vector3.down), out normalchek);
//transform.rotation = Quaternion.FromToRotation(transform.up, normalchek.normal) * transform.rotation;
if (normalchek.distance < 3f && normalchek.transform.gameObject.tag == "grappleable") {
cantmove = false;
//camera.localRotation = (camera.localRotation * Quaternion.Euler(camRot) * Quaternion.Inverse(Quaternion.FromToRotation (transform.up, normalchek.normal)));
//camera.localRotation = (camera.localRotation * Quaternion.Euler(camRot));
//transform.rotation = Quaternion.FromToRotation (transform.up, normalchek.normal) * transform.rotation * Quaternion.Euler (rbRot);
//player.MoveRotation(player.rotation * Quaternion.Euler (rbRot));
transform.rotation = Quaternion.Slerp(player.rotation * Quaternion.Euler (rbRot), Quaternion.FromToRotation (transform.up, normalchek.normal) * transform.rotation * Quaternion.Euler (rbRot), 0.4f);
} else {
player.MoveRotation(player.rotation * Quaternion.Euler (rbRot));
//camera.Rotate (camRot);
}
//wanna rotate to where youre looking at?
RaycastHit normalchek1;
Physics.Raycast (camera.position, camera.transform.forward, out normalchek1);
//Debug.Log(normalchek1.distance);
if (Input.GetKeyDown(KeyCode.Mouse1) && !grounded && normalchek1.transform.gameObject.tag == "grappleable"){
if (normalchek1.distance < grappledist) {
cantmove = true;
player.velocity = new Vector3 (0f, 0f, 0f);
transform.rotation = Quaternion.FromToRotation (transform.up, -(normalchek1.point - camera.transform.position)) * transform.rotation;
if (Random.Range (-1f, 1f) > 0f) {
Instantiate (shock1, transform.position, transform.rotation);
} else {
Instantiate (shock2, transform.position, transform.rotation);
}
} else {
Instantiate (shockfail, transform.position, transform.rotation);
}
}
//moves the camera
camera.Rotate (camRot);
//the float with the "fake" angle
manualangle += camRot.x;
//Debug.Log(camera.localEulerAngles);
if (manualangle > 90f){
camera.localEulerAngles = new Vector3 (90f, 0f, 0f);
manualangle = 90f;
}
if (manualangle < -90f){
camera.localEulerAngles = new Vector3(-90f, 0f, 0f);
manualangle = -90f;
}
#endregion
Answer by uni-TT · May 30, 2020 at 12:22 AM
Ok, I've attempted to solve this on my own but for some reason its all glichy. heres the concept, store the transform.up direction before the rotation and then store another one in a different variable after the rotation. set the x values of both to zero (so vector3.angle cant measure any angles that deviate to the side or anything), and use Vector3.Angle to get the angle between them. then check if the z of the second direction (the direction after the rotation) is positive or negative and use that in an if statement to rotate by the angle negatively, or positively. but when i try this it doesn't work, maybe i'm setting the local x axis wrong? maybe i just don't understand direction vectors. here's the code snippet;
//rotate towards normal
RaycastHit normalchek;
Physics.Raycast (transform.position, transform.TransformDirection(Vector3.down), out normalchek);
//transform.rotation = Quaternion.FromToRotation(transform.up, normalchek.normal) * transform.rotation;
if (normalchek.distance < 3f && normalchek.transform.gameObject.tag == "grappleable") {
cantmove = false;
var storedir1 = transform.up;
transform.rotation = Quaternion.FromToRotation (transform.up, normalchek.normal) * transform.rotation * Quaternion.Euler (rbRot);
var storedir2 = transform.up;
storedir1.x = 0f;
storedir2.x = 0f;
var angle = Vector3.Angle(storedir1, storedir2);
//just to visualize it
if (angle > 0f){
Debug.DrawRay(transform.position, storedir1, Color.red, 5f);
Debug.DrawRay(transform.position, storedir2, Color.blue, 5f);
}
if (storedir2.z < 0f){
camera.Rotate(new Vector3(angle, 0f, 0f));
} else {
camera.Rotate(new Vector3(-angle, 0f, 0f));
}
} else {
player.MoveRotation(player.rotation * Quaternion.Euler (rbRot));
//camera.Rotate (camRot);
}
Answer by uni-TT · Jun 14, 2020 at 09:13 AM
Alright everyone. after like a month, and many nights of randomly thinking about how to solve this issue i figured it out. its currently 3 am and I'm far too tired to understand why it works,and for some reason it also does some funky rotation stuff sometimes which doesn't look right but whatever. here you go:
//rotate towards normal
RaycastHit normalchek;
Physics.Raycast (transform.position, transform.TransformDirection(Vector3.down), out normalchek);
//transform.rotation = Quaternion.FromToRotation(transform.up, normalchek.normal) * transform.rotation;
if (normalchek.distance < 3f && normalchek.transform.gameObject.tag == "grappleable") {
cantmove = false;
var storedir1 = transform.up;
var beforetransform = transform;
transform.rotation = Quaternion.FromToRotation (transform.up, normalchek.normal) * transform.rotation * Quaternion.Euler (rbRot);
storedir1 = beforetransform.InverseTransformDirection(storedir1);
var storedir2 = transform.up;
storedir2 = transform.InverseTransformDirection(storedir2);
storedir1.x = 0f;
storedir2.x = 0f;
storedir1 = transform.TransformDirection(storedir1);
storedir2 = transform.TransformDirection(storedir2);
var angle = Vector3.Angle(storedir1, storedir2);
//just to visualize it
if (angle > 0f){
Debug.DrawRay(transform.position, storedir1, Color.red, 5f);
Debug.DrawRay(transform.position, storedir2, Color.blue, 5f);
}
if (angle > 0f){
Debug.Log(angle);
}
if ((transform.InverseTransformDirection(storedir1).z > 0f)){
camera.Rotate(new Vector3(angle, 0f, 0f));
manualangle += angle;
} else {
camera.Rotate(new Vector3(-angle, 0f, 0f));
manualangle += -angle;
}
//transform.rotation = Quaternion.FromToRotation (transform.up, normalchek.normal) * transform.rotation * Quaternion.Euler (rbRot);
} else {
player.MoveRotation(player.rotation * Quaternion.Euler (rbRot));
//camera.Rotate (camRot);
}
Your answer
Follow this Question
Related Questions
Quaternion values at instantiation. 1 Answer
Rotate on 2 different axes 1 Answer
How to smoothly align an object to a surface, but only partially 2 Answers
Rotation 90.0001 and 1.001719 bugs! 1 Answer
Rotate an object relative to Camera 2 Answers