why am I getting a flipped-out effect from my transform.rotate

I have a hoverboard that adjusts it’s angle depending on the terrain below it. Every so often the board jerks to a strange angle for a moment.
My only guess on why is that the raycasts are hitting joining faces of the terrain ,
And the only solution I can see is somehow logging the last change in angle, if it is an extraordinary leap , then don’t transform.rotate
What is happening, and what should I do / be looking at ? thanks.

  • Edit - the problem actually seems to be a Gimbal Lock.

  • SOLVED with a completely different approach . see answers.

Sample script :

// -- X ANGLE calculations
	// vectorBoardLeft
	if (Physics.Raycast((transform.position + Vector3((widthRaycastX / 2), 0, 0)), Vector3.down, rayHit)) {
		vectorBoardLeft = rayHit.point;
	}
	// vectorBoardRight
	if (Physics.Raycast((transform.position - Vector3((widthRaycastX / 2), 0, 0)), Vector3.down, rayHit)) {
		vectorBoardRight = rayHit.point;
	}
	// calculate X angle
	differenceYX = vectorBoardLeft.y - vectorBoardRight.y;
	angleBoardXtan = differenceYX / widthRaycastX;
	angleBoardRotZ = Mathf.Rad2Deg*Mathf.Atan(angleBoardXtan);
	
	// -- rotate board to align to terrain (Z angle is on the X-axis, and vice verca)
	transform.rotation = Quaternion.Euler (angleBoardRotX, 0, angleBoardRotZ);

webplayer publish : http://www.alucardj.net16.net/unityquestions/hoverboard%201-1b.html

full script : http://www.alucardj.net16.net/unityquestions/ScriptHoverBoard2.js

  • I have just changed the Title of this post as the problem seems to be as described by Kryptos below (thanks for the pointer).
  • I have just changed the Title of this post as I have inadvertently stirred controversy , and created a conversation that is off-topic . Very sorry to all involved :slight_smile:

The easiest way is to align the character to the terrain normal, like @Dakwamine suggested - but smoothly, or it will shake a lot.

The script below keeps the alignment relative to the ground. It doesn’t take care of movement or gravity, what I suppose you’re doing in another script.

private var curNormal: Vector3 = Vector3.up; // smoothed terrain normal
private var iniRot: Quaternion; // initial rotation

function Start(){
    iniRot = transform.rotation;
}

function Update(){
    var hit:RaycastHit;
    if (Physics.Raycast(transform.position, -curNormal, hit)){
        // curNormal smoothly follow the terrain normal:
        curNormal = Vector3.Lerp(curNormal, hit.normal, 4*Time.deltaTime);
        // calculate rotation to follow curNormal:
        var rot = Quaternion.FromToRotation(Vector3.up, curNormal);
        // combine with the initial rotation:
        transform.rotation = rot * iniRot;
    }
}

I answered a question some time ago where a complete CharacterController movement, gravity and terrain alignment were provided by a single script (in C# - click here to see it).

Atan always gives a “forward” result – if you’re going backwards it gives you exactly 180 degrees flipped as the answer. In other words, as you turn it will tell you 87, 88, 89,90,-89, -88,… . That’s not Unity – it’s math.

Most people use Atan2 to solve that – instead of the slope, you give it y and x (differenceYX and widthRaycast) and it takes care of division by zero and backwards, to give correct 0-360 answers.