problems with quaternion rotations

hi there my friends i have a trouble in making the following:
1-i have a spaceship that is controlled by using (rigidbody.AddRelativeTorque) thats is getting info from the position of the mouse on screen.
2-i have a turret on top of the ship.
3-the turret uses the following script to lead the targets:

#pragma strict
#pragma implicit
#pragma downcast

var damping = 5.0;
var Target : GameObject;
var projSpeed : int;
var fireHitRatio : float;
var targetLead : GameObject;
var enableFire : boolean;
var rotation : Quaternion;

function Start(){
 fireHitRatio = 1.15;
} 

function Update () {
 if (Target != null){
 TargetLead();
 }else if (Target == null){
 NoTargets();
 }
}

function TargetLead(){
 if (Target != null) {
   var TGV = Target.rigidbody.velocity;
      projectileSpeed = projSpeed;
      var distTarget = Vector3.Distance(Target.transform.position, transform.position);
      velocityPosition1 = Target.transform.position + ((TGV * fireHitRatio) * (distTarget/projectileSpeed));
      velocityDist1 = Vector3.Distance(velocityPosition1, transform.position);
      velocityPosition2 = Target.transform.position + ((TGV * fireHitRatio) * (velocityDist1/projectileSpeed));
      velocityDist2 = Vector3.Distance(velocityPosition2, transform.position);
      TargetInterceptPosition = Target.transform.position + ((TGV * fireHitRatio) * (velocityDist2/projectileSpeed));
      
      rotation = Quaternion.LookRotation((TargetInterceptPosition) - transform.position);
   transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * damping);
 }
 targetLead.transform.position = camera.main.WorldToViewportPoint(TargetInterceptPosition);
}

function NoTargets(){
 targetLead.transform.position = Vector3(0,0,0);
 transform.rotation = Quaternion.Slerp(transform.rotation, transform.parent.rotation, Time.deltaTime * damping / 5);
}

4-the turret must be alinged with the ship at all times , but must also try to look at the target lead with the following:

the above script works the best if used on a turret made with 1 piece of geometry.

the turret is made up with 2 parts ,(turret) which moves only on Y Axis , (barrel) which moves only on X Axis but also follows the turret Y Axis.

the troubles i am having:
1-used many scripts , cant list them here but it always mess the rotation of the turret by a really weird rotations.
2-the following script is the best but it does not aim well , it aims little higher than it must be:

    var rotationInfo : ProcessingTargets;
var displayedInfo : Quaternion;


function Update (){
 displayedInfo = Quaternion.Slerp(transform.rotation, rotationInfo.rotation, Time.deltaTime * rotationInfo.damping);
 if (rotationInfo.Target != null){
 transform.rotation = Quaternion(displayedInfo.x,displayedInfo.y,displayedInfo.z,displayedInfo.w);
 Debug.DrawLine(transform.position,rotationInfo.Target.transform.position,Color(1,1,1,1));
 }
}  

var turretRotationsInfo : TurretTargeter;
var angle = 0.0;
var axis : Vector3;
var isBarrel : boolean;

function Update (){
 axis = turretRotationsInfo.displayedInfo.eulerAngles;
 if(isBarrel == false){
 transform.localEulerAngles.y = axis.y - 90;
 }else if(isBarrel == true){
 transform.localEulerAngles.y = axis.x + 1.5;
 }
} 

please i wish someone really helps me with this because it have taken a long time in debugging , trying , scripting …etc

and also i am having lot of troubles with (quaternions) i have read the documents on it but still didnt understand it fully and i think thats why i failed at fixing this.

thx in adv

I didn’t understand exactly what your script should do, but you should not mix eulerAngles with localEulerAngles - localEulerAngles are the angles relative to the parent transform, and you should take the parent rotation into account before setting them. Furthermore, eulerAngles aren’t too reliable - eulerAngles are actually the transform.rotation converted to 3-axes representation on the fly; since there are several XYZ combinations equivalent to any possible rotation, Unity sometimes selects a weird one to return, driving us crazy.

I think the simplest solution would be just to use transform.LookAt(target) in the turret script:

var target: Transform;

function Update(){
  transform.LookAt(target);
}

If you want to follow the target with some delay, use this:

var target: Transform;

function Update(){
  var dir = target.position - transform.position;
  var rot = Quaternion.LookRotation(dir); // LookRotation takes a direction as argument
  transform.rotation = Quaternion.Slerp(transform.rotation, rot, damping * Time.deltaTime);
}

EDITED: If you want to rotate the turret and the barrel around their local Y and X axes, respectively, there’s a “dirty trick” that can split movements: for the turret, transform the target position in local space with InverseTransformPoint, zero its Y coordinate and convert it back to world space with TransformPoint - this will project the target position in the turret’s local horizontal plane; you can then use Quaternion.LookRotation to find the desired rotation, and Slerp to it. You could also repeat the trick for the barrel (zeroing its X coordinate instead, so that the point would be projected in the barrel’s vertical plane), but it’s not advisable: errors accumulated over time will cause a deviation. It’s better to just use LookRotation to find the necessary rotation to the target position and Slerp the barrel to it - the result is the same, but you’ll not get accumulated errors:

EDITED2: You’re right: the turret was using its local space to find the point, and gradually this reference was being lost, giving very weird rotations. I changed the things a little: created an empty object (let’s call it Ref) at the turret position, added the script below to it, then childed the turret and the barrel to the Ref object - the hierarchy is as follows:

Ship <- ship is parent of the Ref object
  Ref <- control script goes here
    Barrel <- barrel is childed to Ref
    Turret <- turret is childed to Ref

The script caches references to Barrel and Turret, and control both:

var target: Transform;
var damping: float = 5.0;

private var turret: Transform;
private var barrel: Transform;
private var trf: Transform;

function Start () { // the barrel is a turret's child:
  trf = transform;
  barrel = trf.Find("Barrel");
  turret = trf.Find("Turret");
}

function Update () {
  // convert target position to local space:
  var pos = trf.InverseTransformPoint(target.position);
  pos.y = 0; // project it in the horizontal plane
  // convert pos back to world space:
  pos = trf.TransformPoint(pos);
  // find the desired turret rotation and Slerp to it:
  var rot = Quaternion.LookRotation(pos-trf.position, trf.up);
  turret.rotation = Quaternion.Slerp(turret.rotation, rot, damping*Time.deltaTime); 
  // just point the barrel to the target:
  rot = Quaternion.LookRotation(target.position-barrel.position, trf.up);
  barrel.rotation = Quaternion.Slerp(barrel.rotation, rot, damping*Time.deltaTime); 
}

I had the same freaking problem and worked around it like this.

Here the corpus and barrel are handled. Both transformations are reduced to a 1 or 2 dimensional rotation. I use a temp look-at vector to work around quaternions.

I stripped all the code for shooting particle control and some other stuff.

!! For this to work, the barrel must be an individual model and has to have it’s origin at it’s rotation point

If you only want to rotate the whole turret (corpus) then just stip the barrel code.

 // C#
 public Transform corpus;
 public float corpusTurnSpeed = 10.0f;
 public Transform barrel;
 public float barrelTurnSpeed = 10.0f;
 
 private GameObject currentTarget = null;
    
 void Update ()
 {
    // Stripped ....
             
    if (currentTarget != null) {
       Vector3 targetPoint = currentTarget.collider.bounds.center;

       // Calculate Corpus X-Y-Z Rotation and LERP it
       // then set Corpus Y Rotation to 0.0
       Vector3 newCorpusFwd 
          = Vector3.Lerp (corpus.forward, 
             (targetPoint - corpus.position).normalized,
             Time.deltaTime * corpusTurnSpeed);
       newCorpusFwd.y = 0.0f;
       corpus.transform.forward = newCorpusFwd;

       // Calculate Barrel Y Rotation and smoothStep it
       // Then align Barrel x-z rotation to the corpus again
       barrel.transform.LookAt (targetPoint);
       Vector3 newBarrelFwd = barrel.forward;
       float newBarrelY
          = Mathf.SmoothStep (barrel.forward.y, 
             (targetPoint - barrel.position).normalized.y,
             Time.deltaTime * barrelTurnSpeed);
       newBarrelFwd.x = newCorpusFwd.x;
       newBarrelFwd.y = newBarrelY;
       newBarrelFwd.z = newCorpusFwd.z;
       barrel.forward = newBarrelFwd;
 
       // Stripped ...
    
    } else {
       // Stripped ... 
    }
 }

As requested, here the javascript version, but not tested:

 // javascript
 var corpus : Transform;
 var corpusTurnSpeed : float = 10.0f;
 var barrel : Transform ;
 var barrelTurnSpeed : float = 10.0f;
 
 private var currentTarget : GameObject;
    
 void Update ()
 {
    // Stripped ....
             
    if (currentTarget != null) {
       var targetPoint : Vector3 = currentTarget.collider.bounds.center;

       // Calculate Corpus X-Y-Z Rotation and LERP it
       // then set Corpus Y Rotation to 0.0
       var newCorpusFwd : Vector3
          = Vector3.Lerp (corpus.forward, 
             (targetPoint - corpus.position).normalized,
             Time.deltaTime * corpusTurnSpeed);
       newCorpusFwd.y = 0.0f;
       corpus.transform.forward = newCorpusFwd;

       // Calculate Barrel Y Rotation and smoothStep it
       // Then align Barrel x-z rotation to the corpus again
       barrel.transform.LookAt (targetPoint);
       var newBarrelFwd : Vector3 = barrel.forward;
       var newBarrelY : float
          = Mathf.SmoothStep (barrel.forward.y, 
             (targetPoint - barrel.position).normalized.y,
             Time.deltaTime * barrelTurnSpeed);
       newBarrelFwd.x = newCorpusFwd.x;
       newBarrelFwd.y = newBarrelY;
       newBarrelFwd.z = newCorpusFwd.z;
       barrel.forward = newBarrelFwd;
 
       // Stripped ...
    
    } else {
       // Stripped ... 
    }
 }

ok this Script works semi fine:

var turretRotationsInfo : TurretTargeter;
var angle = 0.0;
var axis : Vector3;
var isBarrel : boolean;

function Update (){
 axis = turretRotationsInfo.displayedInfo.eulerAngles;
 if(isBarrel == false){
 transform.localEulerAngles.y = axis.y - 90;
 }else if(isBarrel == true){
 transform.localEulerAngles.y = axis.x + 1.5;
 }
}

but as soon as i move the ship , the turrets starts to inherit some added rotation from the ship so it starts missing the right point to aim to.

any fix for this?

please help me at least with a hint only.

hi again , sigh , i tried everything above and trying to combine it with my code of lead targeting but nothing worked probably, so here i am asking a fix for it as the following:
i will have to write it in the answers cuz i didnt find how i can format the code using comments , if its wrong to do it like that then i am sorry , i will remove it.

i have this script:

#pragma strict
#pragma implicit
#pragma downcast

var damping = 5.0;
var Target : GameObject;
var projSpeed : int;
var fireHitRatio : float;
var targetLead : GameObject;
var targetLead2 : GameObject;
var targetLead3 : GameObject;
var shiproty : Transform;

function Start(){
 fireHitRatio = 1.15;
} 

function Update () {
 if (Target != null){
 TargetLead();
 }else if (Target == null){
 NoTargets();
 }
 
}

function TargetLead(){
 if (Target != null) {
   var TGV = Target.rigidbody.velocity;
      projectileSpeed = projSpeed;
      var distTarget = Vector3.Distance(Target.transform.position, transform.position);
      var velocityPosition1 = Target.transform.position + ((TGV * fireHitRatio) * (distTarget/projectileSpeed));
      var velocityDist1 = Vector3.Distance(velocityPosition1, transform.position);
      var velocityPosition2 = Target.transform.position + ((TGV * fireHitRatio) * (velocityDist1/projectileSpeed));
      var velocityDist2 = Vector3.Distance(velocityPosition2, transform.position);
      var TargetInterceptPosition = Target.transform.position + ((TGV * fireHitRatio) * (velocityDist2/projectileSpeed));

      var rotation = Quaternion.LookRotation((TargetInterceptPosition) - transform.position);
   transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * damping);
   
 }
 
 targetLead.transform.position = camera.main.WorldToViewportPoint(velocityPosition1);
 targetLead2.transform.position = camera.main.WorldToViewportPoint(velocityPosition2);
 targetLead3.transform.position = camera.main.WorldToViewportPoint(TargetInterceptPosition);
}

all i want is to split the rotations from it in to X , Y , Z and store them in Vars , then convert them in to local rotations.

i prefer to not change the code of leading targets cuz its working the best and i couldn’t find another way to do it.

please this problem have taken from me most of my Time , still i thank everyone who tried to help me with it.

thx in adv