Hover effect : raycasting problems with terrain height and speed

Hi everybody,

I’m a new Unity user. Here is my project (I plan to program a Wipeout clone) : http://dl.dropbox.com/u/12575338/WebPlayer.html

I have 2 problems with the hover effect :

The first problem appears when the ship is above the lower altitude of the ground : there is a small rotation around the y-axis (about 2 degrees) and the ship then returns to its starting rotation. Then resumes its small rotation, etc… When the ship in above a mountain, or is climbing, there’s no problem.

Here is the relevant code :

            RaycastHit hit;

            for (int i = 0; i <= corners.Length - 1; i++)
            {
                if (Physics.Raycast(corners_.position, -corners*.up, out hit, hoverHeight+100))*_

{
if (hit.collider.gameObject.tag == “Terrain”)
{
hitNormal = body.transform.InverseTransformDirection(hit.normal);

if (lastNormals != hitNormal*)*
{
increment = 0;
lastNormals = hitNormal*;*
}

distance = hit.distance;

}
}
}
average = -(hitNormal[0] + hitNormal[1] + hitNormal[2] + hitNormal[3] + hitNormal[4]) / 5;

* if (increment != 1)*
{
increment += 0.03f;
}

_ rotation = Quaternion.Slerp(body.transform.localRotation, Quaternion.Euler(average * Mathf.Rad2Deg), increment);
rotation.y = transform.up.y*Mathf.Deg2Rad;
I set up 5 positions on my ship (stored in the array “corners[5]”) from which I launch a ray down. If the ray collides with the terrain, I store the normal in my hitNormal[] array. Then I calculate the average of these normals, and I set up the rotation of my ship according to the result.
After debbuging, I noticed that the normals vary a lot when the ship is above the lower altitude of the terrain. So the average varies too, and that’s what make this glitch around the y-axis. And I don’t understand why it varies only above the lower altitude and not higher or when climbing.
Another problem : when the ship climbs slowly, it hovers correctly along the side of the hill. But in high speed, it goes through the hill. Note that I have no Collider on my ship, and I move it in FixedUpdate() with AddForce.
Can you help me ? Thanks a lot_

(converted to an answer, as I looked more into your code, and more problems/suggestions arised)

Harkonnen, you cannot manipulate Quaternions this way. Well, you can, but it doesn’t have your intended result, as “rotation.y” is something entirely different as the rotation around the y axis. A real quaternion is normalized over all four paramerers xyzw, the “Quaternion” class does not store its parameters in an Axis-Angle representation.

What you probably want to do is manipulate eulerAngles.y instead.

EDIT: just looked at your code more closely. Of yourse you don’t have an “eulerAngles” fields, I thought we were talking about a transform. You’d somehow need to work on eulerAngles instead. And another thing, “average * Mathf.Rad2Deg” doesn’t make sense either, Quaternion.Euler() expects three angles in degrees, but you are giving it the normal vector, converted to degrees, neither of which makes sense.

EDIT2: Hm, there are too many logical errors in your code, it might be better to start from scratch after reading some tutorials, or finding examples doing a simliar thing (for example, you could look into a ship/buoy floater script, which does a similar thing).

Things that will not work:

  • You’re replacing hitNormal only if there is an actual hit with a Terrain tagged object. If for some reason there is a different collider inbetween, you won’t update that hitNormal, but will still use the old value for averaging.
    - You cannot average normal vectors by just adding them together and dividing by the number of vectors. Normalize the sum, instead of dividing.
    - As mentioned above, you can’t feed Quaterion.Euler the values you do
    - And you can’t manipulate Quaternions the way you do.
    Instead I’d suggest the following:
    - Fix your code that it correctly averages all hit.normals, and only those that actually come from the current Terrain test.
    - Stay away from Quaternion manipulation and functions, unless you know exactly how they work, and how they are handled inside Unity.
    - Instead, I’d suggest to do a simple Vector3.Slerp betweeen the current transform.up and your averaged world spacenormal (not local space! so lose the InverseTransformDirection). This should smoothly orient your transform along that normal, and leave the other orientation vectors alone (well, at least the Y angle - the X angle will need to change per definition of the euler angle rotation order, as your ship changes pitch).
    - As the “t” value of your Slerp, use Time.deltaTime*smoothnessFactor, as you will see in 99% of all Unity Answers questions dealing with Lerp/Slerp. This will “abuse” the functionality of the Lerp (because it’s no longer a real linear interpolation), but it will do the task as most people intend to.