- Home /
Can't figure out how to make my raycast obstacle avoidance less jittery
I'm currently using a raycast obstacle avoidance solution that I cobbled together, and it works okay, but has a few problems.
Chief among them is that when my AI object is avoiding, it is very jittery. I know exactly why its jittery, because I'm adding the hit.normal (multiplied by a modifier) of the raycast to my target direction for my eventual slerp, so the frames that the AI is avoiding the target direction is instantly changed, resulting in a jitter.
I know I need to probably Vector3.Lerp my avoidance direction (the original target direction plus the offset from the raycast hit.normal) and my original target direction, I just have no idea where to put it!
Here's my whole script in its current incarnation:
var rayLength : float = 10.0;
private var rayArray : Vector3[];
function Start(){ rayArray = new Vector3[3]; }
function MoveTowardsAndAvoid(target : Transform, speed : float, rotSpeed : float){
var targetPos : Vector3 = target.position;
targetPos.y = transform.position.y; //set y to zero so we only rotate on one plane
var targetDir : Vector3 = targetPos - transform.position;
rayArray[0] = transform.TransformDirection(-0.20,0,0.5); //ray pointed slightly left
rayArray[2] = transform.TransformDirection(0.20,0,0.5); //ray pointed slightly right
rayArray[1] = transform.forward; //ray 1 is pointed straight ahead
//loop through the rays
for (i=0; i<3; i++) {
var hit : RaycastHit;
// if you hit something with the ray......
if (Physics.Raycast (transform.position, rayArray[i], hit, rayLength)) {
Debug.DrawLine(transform.position, hit.point, Color.magenta);
targetDir += 50*hit.normal;
}
}
// rotation and movement code
var targetRotation = Quaternion.LookRotation(targetDir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotSpeed*Time.deltaTime);
transform.Translate(Vector3.forward*Time.deltaTime*speed);
}
Any ideas?
Did you end up solving this Derek?
I'm having the a very similar problem using a single raycast to rotate a gameobject based on the hit.normal and Quaternion.LookRotation(dir). It gets quite jittery only during the obstacle avoidance, otherwise it's very smooth. I have posted a question about it here: How to apply dampening to hit normal based rotation?
Would really appreciate some help about this from someone, or even an alternative approach.
Answer by reissgrant · Feb 07, 2011 at 12:58 AM
Try this:
var rayLength : float = 10.0; var lerpSpeed : float = 1.0; var theTarget : GameObject; var mult : float = 1.0; var speed : float = 1.0; var rotSpeed : float = .15;
private var rayArray : Vector3[]; private var lerpedTargetDir : Vector3;
function Start(){ rayArray = new Vector3[3]; }
function Update(){
MoveTowardsAndAvoid(theTarget.transform);
}
function MoveTowardsAndAvoid(target : Transform){
var targetPos : Vector3 = target.position;
targetPos.y = transform.position.y; //set y to zero so we only rotate on one plane
var targetDir : Vector3 = targetPos - transform.position;
rayArray[0] = transform.TransformDirection(-0.20,0,0.5); //ray pointed slightly left
rayArray[2] = transform.TransformDirection(0.20,0,0.5); //ray pointed slightly right
rayArray[1] = transform.forward; //ray 1 is pointed straight ahead
moveIt = false;
//loop through the rays
for (i=0; i<3; i++) {
var hit : RaycastHit;
// if you hit something with the ray......
if (Physics.Raycast (transform.position, rayArray[i], hit, rayLength)) {
Debug.DrawLine(transform.position, hit.point, Color.magenta);
targetDir += mult * hit.normal;
} else {
moveIt = true;
}
}
// rotation and movement code
lerpedTargetDir = Vector3.Lerp(lerpedTargetDir,targetDir,Time.deltaTime * lerpSpeed);
var targetRotation = Quaternion.LookRotation(lerpedTargetDir);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotSpeed*Time.deltaTime);
if(moveIt){ transform.Translate(Vector3.forward*Time.deltaTime*speed); }
}
Nah, I tried something basically just like this (and just tried yours just to be safe). It bounces slowly bounces back and fourth slowly now, like a more pronounced jitter.
You can try increasing the lerp speed variable to 10, then 100 to see if it helps. Sorry, I don't have the accompanying code to test this.
Ah ok I setup a test scene, that lerpspeed doesn't help. I'll see if theres something else that can be done.
I set the lerpSpeed to 1 and rotSpeed to .1 and I get nice smooth rotations.
is probably too smooth though.
I updated my code above to get smooth rotations, also it only moves if there is an open path.
Answer by Jesse Anders · Feb 07, 2011 at 02:21 AM
One thing you might try is to respond only to one of the raycasts, rather than (potentially) to all three. For example, you could respond to the closest one, or to the one for which the normal is most aligned towards the agent.
I'd also recommend consulting the literature on steering behaviors (or reviewing it, if you've already covered that material). These behaviors are all pretty well defined, and you can find example implementations in libraries such as OpenSteer, UnitySteer etc. By looking at how it's done elsewhere (or just reading the description in the 'canonical' paper on the subject) and comparing it to what you're doing, you should be able to figure out what's causing the problem.
Sorry to be a little vague, but to offer a specific suggestion I'd probably have to dig into the code myself. In the meantime though, perhaps the above suggestions will be of some help.
The documentation for UnitySteer seems deliberately obtuse or borderline nonexistent, but I would love to use it if I could. It doesn't seem too easy to implement into your own AI scripts without being forced to use their vehicle scripts and code around it.
Answer by DaveA · Feb 07, 2011 at 07:59 PM
What if you put the 'move' stuff in Update() and the 'find' stuff in LateUpdate()?
What do you mean? If the move/rotate stuff was in Update() and I need to modify the targetDir of my rotation slerp when I hit an obstacle, how would I modify the rotation after it already happened?