2dkot
1
I try to rotate object according normal rotation of terrain. More over this object should move. And I need to combine z and x from normal of terrain and y which rotates to target. I tried this but result is quiet weird:
function getTerrainRot(myTarget:Vector3,terrPos: Vector3,modelRot:Quaternion){
var terrHit: RaycastHit;
var dirQuat: Quaternion;
var newPos: Vector3;
if(Physics.Raycast (terrPos, -Vector3.up,terrHit, 10.0))
{
newPos = getPosAndTerrainY(myTarget) - terrPos;
normal_q = Quaternion.FromToRotation(Vector3.up, terrHit.normal);
terr_q = normal_q * Quaternion.AngleAxis(modelRot.eulerAngles.x, terrHit.normal);
dirQuat = Quaternion.LookRotation(newPos);
terr_q = Quaternion(terr_q.x,dirQuat.y,terr_q.z,dirQuat.w);
}
return Quaternion.Slerp(modelRot, terr_q, Time.deltaTime);
}
Thanks
You’re having weird results because you’ve messed with the components of a Quaternion - despite their names, they have nothing to do with the axes x, y and z.
If you want the character to keep looking to newPos direction while following the surface normal, you can use LookRotation(newPos, normal) - the second parameter indicates the up direction. About the surface normal: it’s better to keep a curNormal variable and Lerp it to the surface normal (or Vector3.up, if no terrain hit) to smooth the character orientation:
var curNormal = Vector3.up;
function getTerrainRot(myTarget:Vector3,terrPos: Vector3): Quaternion; {
var terrHit: RaycastHit;
var newPos: Vector3;
var normal = Vector3.up;
if(Physics.Raycast (terrPos, -curNormal, terrHit, 10.0)){
normal = terrHit.normal;
}
curNormal = Vector3.Lerp(curNormal, normal, 2*Time.deltaTime);
newPos = getPosAndTerrainY(myTarget) - terrPos;
return Quaternion.LookRotation(newPos, curNormal);
}
EDITED: You’re right: LookRotation in this case doesn’t work as expected - it prefers to look at the target direction and completely ignores the normal!
Let’s go back to the basics: calculate a rotation from Vector3.up to curNormal (as you already did), than multiply by the horizontal rotation from Vector3.forward to the target direction (multiplication in the Quaternion world actually combines the rotations):
var curNormal = Vector3.up;
function getTerrainRot(myTarget:Vector3,terrPos: Vector3): Quaternion {
var terrHit: RaycastHit;
var newPos: Vector3;
var normal = Vector3.up; // default normal = up
if (Physics.Raycast (terrPos, -curNormal, terrHit, 10.0)){
normal = terrHit.normal; // use the surface normal, if any
} // smoothly follow the surface normal
curNormal = Vector3.Lerp(curNormal, normal, 2*Time.deltaTime);
newPos = myTarget - terrPos; // get the direction to look at
newPos.y = 0; // zero y to keep only the horizontal direction
// calculate rotation to normal
var rot = Quaternion.FromToRotation(Vector3.up, curNormal);
// combine with the horizontal rotation
rot = rot * Quaternion.FromToRotation(Vector3.forward, newPos);
return rot;
}