- Home /
quaternion.slerp issue
I am trying to make an enemy turn to face my character on the Y axis and make the arms move on the X axis so that the guns on the end of the arms are pointing at me.
The the arms are a seperate object but are atteached to the enemy so if it turns so do they.
I have both sets of rotations working properly but if I have both running at the same time then it starts affecting the arm's Y axis even though the code explicitly removes any Y axis movement from the arms. The only Y rotation should come directly from the enemy but that shouldn't show in the arm's rotation in the inspector and in this it is changes even though the slerp fuction should be moving it between 0 and 0 on the Y and Z axes.
This is the code now:
var arms:GameObject;
var leftGun:GameObject;
var rightGun:GameObject;
var bullet:GameObject;
private var lastKnownPlayerLocation:Transform;
private var currentAimAngle:float;
function Update () {
aim();
}
function aim(){
var newRotation = Quaternion.LookRotation(lastKnownPlayerLocation.position - this.transform.position, Vector3.up);
newRotation.x = 0.0;
newRotation.z = 0.0;
transform.rotation = Quaternion.Slerp (transform.rotation, newRotation, Time.deltaTime * 5.0);
var new2Rotation = Quaternion.LookRotation (lastKnownPlayerLocation.position - arms.transform.position, Vector3.up);
new2Rotation.y = 0.0;
new2Rotation.z = 0.0;
arms.transform.rotation = Quaternion.Slerp (arms.transform.rotation, new2Rotation, Time.deltaTime * 5.0);
}
Answer by chainedlupine · May 03, 2012 at 07:53 PM
Two problems that I see. First, you're treating the quaternion x/y/z components as if they are Euler angles -- which they aren't. You can get the canonical euler angles of a rotation using the eulerAngles property. (And you can convert them back into quaternion notation using Quaternion.Euler.)
Secondly, you're doing a world-transform manipulation of the arms, which complicates things. I would just modify the localRotation. (Note I assume your arms are children of the object that is doing these calculations.)
So, taking those two into account:
Quaternion newRotation = Quaternion.LookRotation(lastKnownPlayerLocation.position - transform.position, Vector3.up);
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.Euler (0, newRotation.eulerAngles.y, 0), Time.deltaTime * 5.0f);
Quaternion new2Rotation = Quaternion.LookRotation (lastKnownPlayerLocation.position - arms.transform.position, Vector3.up);
arms.localRotation = Quaternion.Slerp (arms.localRotation, Quaternion.Euler (new2Rotation.eulerAngles.x, 0, 0), Time.deltaTime * 5.0f);
Note that I do not use JS, so it is an exercise left to the questioner to convert this to JS:
For sake of completeness, here is what localRotation is doing internally, at least expressed in terms of quaternion rotations:
arms.rotation = Quaternion.Slerp (arms.rotation, transform.rotation Quaternion.Euler (new2Rotation.eulerAngles.x, 0, 0), Time.deltaTime 5.0f);
Again, assu$$anonymous$$g player->arms relationship.
Though this is written differently it still produces the same issues.
When I move to the right whilst facing the enemy the arms seem to rotate to the left very slightly.
The arms do in fact do the part that I want them to do in that they rotate to point up and down relative to the player's position it's just that as the enemy rotates on the Y axis the arms don't.
Additional note:
I still don't know why it did what it did but I managed to fix it by adding this at the end to reset the local y and z axis for the arms:
arms.transform.localRotation.eulerAngles.y = 0; arms.transform.localRotation.eulerAngles.z = 0;
Answer by Bunny83 · May 04, 2012 at 01:28 AM
You can calculate the rotation manually. Since you only need one angle is't not that hard ;) Assuming the enemy already faces the player, you just need to calculate the arcsin.
Vector3 dir = lastKnownPlayerLocation.position - arms.transform.position;
float opposite = dir.y;
float hyp = dir.magnitude;
float angle = Mathf.Asin(opposite / hyp) * Mathf.Rad2Deg;
arms.transform.localEulerAngles = new Vector3(angle,0,0);
Haven't tried the code, maybe you need to invert the angle
Smart solution! dir.y/dir.magnitude returns the sine of the elevation angle, which is converted to degrees and used to set the X local Euler angle directly
Answer by aldonaletto · May 04, 2012 at 01:51 AM
When you modify the quaternion's components that way you're producing non-normalized quaternions, which may cause erroneous rotations. As @chainedlupine also said, you should not mix rotations and local rotations. You should find the target direction and zero its Y component to keep it horizontal, and get the local target direction and zero its X component to keep it vertical, then Slerp rotation to the horizontal direction and Slerp localRotation to the vertical direction - like this:
function aim(){ // dirH = player direction var dirH = lastKnownPlayerLocation.position - this.transform.position; // dirV = arms local player direction var dirV = arms.transform.InverseTransformDirection(dirH); dirH.y = 0; // keep dirH strictly horizontal dirV.x = 0; // keep dirV strictly vertical var newRotH = Quaternion.LookRotation(dirH, Vector3.up); var newRotV = Quaternion.LookRotation(dirV, Vector3.up); transform.rotation = Quaternion.Slerp (transform.rotation, newRotH, Time.deltaTime * 5.0); arms.transform.localRotation = Quaternion.Slerp (arms.transform.localRotation, newRotV, Time.deltaTime * 5.0); }
Answer by DannyLZS · May 04, 2012 at 12:16 AM
why not just set the arms to the parents facing rotation ? and save yourself the trouble of trying to work it out ?
As a child of the enemy (which it already is) the arms should inherit any world space rotations. For some reason the script altered the arms local y and z axes which countered the world space rotation and left the arms facing the wrong way on the y and z axes.
The whole point is that the entire enemy turns in the y axis but only the arms turn in the x axis.
Answer by DannyLZS · May 04, 2012 at 01:46 AM
Get rid of trying to calculate a whole new rotation for the arms and let them be dragged around the Y axis by its parent. Then when you check that it is facing the correct way rotate the arms localEularAngles.x up or down by a few degrees until the Dot Product is within a zone where you want it ? I could hash up this code for you if you like but this is just off the top of my head
Your answer
Follow this Question
Related Questions
doing force and spin on a gameobject when clicking on plane. 2 Answers
Unity Null Reference Error 1 Answer
UNITY_MVP_MATRIX error when downloading A* Pathfinding 1 Answer
3 errors in scrip. 1 Answer